API Contract

API Contract for shinyseo

This page is written so another agent can use the package without reading the source.

Exported surface

  • social_meta(meta) — builds and injects metadata tags into the page <head> at startup.
  • update_meta(session, title, description, url, image) — reactively updates one or more metadata fields from the server at runtime.
  • write_manifest(meta, path, display, start_url, background_color) — writes a manifest.json to www/ so Shiny can serve it.

Return value

social_meta() returns a shiny::tags$head() fragment.

You normally place it inside a Shiny UI definition, for example:

shinyseo::social_meta(list(
  title = "Hello",
  description = "Short app description.",
  url = "https://example.no",
  image = "https://example.no/share.png"
))

Input contract

meta can be one of:

  • a character string containing a path to a YAML file
  • a named list of metadata values

If meta is a character string, the package reads it with yaml::read_yaml().

If the file does not exist, the function stops with:

  • Meta file not found: <path>

Required fields

These keys must exist in the final metadata object:

  • title
  • description
  • url
  • image

The function checks only that the names exist. It does not currently validate that the values are non-empty strings.

If any required key is missing, the function stops with:

  • Missing required meta fields: ...

Defaults

The package fills these defaults when the key is missing or NULL:

  • locale = "en_US"
  • robots = "index,follow,max-image-preview:large,max-snippet:-1,max-video-preview:-1"
  • twitter_card = "summary_large_image"
  • bing_site_verification = Sys.getenv("SHINYSEO_BING_SITE_VERIFICATION") when present
  • twitter_site = Sys.getenv("SHINYSEO_TWITTER_SITE") when present
  • twitter_creator = Sys.getenv("SHINYSEO_TWITTER_CREATOR") when present
  • schema_type = "WebApplication"
  • operating_system = "Any"
  • author_type = "Person"
  • publisher_type = "Organization"
  • in_language = locale

Important detail:

  • schema is enabled unless it is exactly FALSE
  • schema = TRUE, schema = NULL, or an omitted schema field all result in JSON-LD output
  • schema = FALSE suppresses JSON-LD
  • The helper does not emit a <title> tag; set the document title in the app UI so it does not clash with any title Shiny already sets

Output tags

The function writes these tags into the returned head fragment:

  • <link rel="canonical" href="...">
  • <meta name="description" ...>
  • <meta name="robots" ...>
  • Open Graph tags used by Facebook, LinkedIn, Slack, X, and other platforms that read Open Graph:
    • og:type = website
    • og:title
    • og:description
    • og:url
    • og:image
    • og:site_name when site_name is present
    • og:locale when locale is present
    • og:image:width when image_width is present
    • og:image:height when image_height is present
    • og:image:type when image_type is present
    • og:image:alt when image_alt is present
  • Twitter Card tags:
    • twitter:card
    • twitter:title
    • twitter:description
    • twitter:image
    • twitter:url
    • twitter:site when twitter_site is present
    • twitter:creator when twitter_creator is present
    • twitter:image:alt when twitter_image_alt is present
  • Bing verification:
    • msvalidate.01 when bing_site_verification is present
  • Google verification:
    • google-site-verification when google_site_verification is present
  • Yandex verification:
    • yandex-verification when yandex_site_verification is present
  • Baidu verification:
    • baidu-site-verification when baidu_site_verification is present
  • Naver verification:
    • naver-site-verification when naver_site_verification is present
  • Facebook domain verification:
    • facebook-domain-verification when facebook_domain_verification is present
  • Pinterest domain verification:
    • p:domain_verify when pinterest_domain_verification is present
  • Schema.org JSON-LD:
    • only when schema is not FALSE
    • always includes @context, @type, name, description, url, and inLanguage
    • conditionally includes applicationCategory, operatingSystem, educationalUse, isAccessibleForFree, disclaimer, author, and publisher

Field map

Key Used for
title Open Graph title, Twitter title, schema name
description Meta description, Open Graph description, Twitter description, schema description
url Canonical URL, Open Graph URL, Twitter URL, schema URL
image Open Graph image, Twitter image
locale Open Graph locale, schema language default
robots Robots meta tag
twitter_card Twitter card type
twitter_site Twitter site handle; falls back to SHINYSEO_TWITTER_SITE
twitter_creator Twitter creator handle; falls back to SHINYSEO_TWITTER_CREATOR
twitter_image_alt Twitter image alt text
image_alt Open Graph image alt text
image_width Open Graph image width
image_height Open Graph image height
image_type Open Graph image MIME type
bing_site_verification Bing Webmaster verification; falls back to SHINYSEO_BING_SITE_VERIFICATION
google_site_verification Google Search Console verification
yandex_site_verification Yandex Webmaster verification
baidu_site_verification Baidu Webmaster verification
naver_site_verification Naver Webmaster verification
facebook_domain_verification Facebook domain verification
pinterest_domain_verification Pinterest domain verification
schema_type Schema.org @type
application_category Schema.org applicationCategory
operating_system Schema.org operatingSystem
educational_use Schema.org educationalUse
is_accessible_for_free Schema.org isAccessibleForFree
disclaimer Schema.org disclaimer
author_name Schema.org author.name
author_type Schema.org author.@type
publisher_name Schema.org publisher.name
publisher_type Schema.org publisher.@type
in_language Schema.org inLanguage
schema Turns JSON-LD on or off

Favicon and web app manifest fields

These optional fields in social_meta() control browser icon and PWA behaviour:

Field Tag produced
favicon <link rel="icon" type="..." href="...">
favicon_type Overrides the MIME type inferred from favicon’s extension
favicon_png <link rel="icon" type="image/png" sizes="..." href="..."> — PNG fallback alongside an SVG favicon
favicon_png_sizes Overrides the sizes attribute on favicon_png (defaults to "32x32")
apple_touch_icon <link rel="apple-touch-icon" href="...">
manifest <link rel="manifest" href="...">
theme_color <meta name="theme-color" content="...">
short_name Used by write_manifest() for the manifest short_name field

MIME type is inferred automatically from the file extension of favicon (.ico, .png, .svg, .webp, .gif). Supply favicon_type to override.

If favicon is an SVG, also set favicon_png to a PNG fallback. Chromium-based browsers don’t render SVG favicons in the address bar and fall back to a generic globe icon without one.

write_manifest()

Generates www/manifest.json from the same metadata object. Call it once in global.R:

shinyseo::write_manifest(list(
  title            = "My App",
  short_name       = "MyApp",
  description      = "A Shiny web app.",
  theme_color      = "#1a73e8",
  favicon          = "/favicon.png",
  apple_touch_icon = "/apple-touch-icon.png"
))

Then reference the manifest from the UI:

shinyseo::social_meta(list(
  ...,
  manifest = "/manifest.json"
))

Parameters:

  • meta — same YAML path or list as social_meta().
  • path — directory to write into. Defaults to "www".
  • display — PWA display mode: "standalone" (default), "fullscreen", "minimal-ui", or "browser".
  • start_url — start URL in the manifest. Defaults to "/".
  • background_color — splash screen background. Defaults to theme_color when set, otherwise "#ffffff".

update_meta() — reactive metadata updates

update_meta(session, title, description, url, image) sends a custom message to the browser that updates the live DOM without a page reload. It is intended for multi-page or tabbed Shiny apps where the metadata should reflect the current view.

Parameters

  • session — the Shiny session object passed to server.
  • title — replaces document.title, og:title, and twitter:title.
  • description — replaces meta[name="description"], og:description, and twitter:description.
  • url — replaces link[rel="canonical"], og:url, and twitter:url.
  • image — replaces og:image and twitter:image.

All parameters except session are optional. Only the fields you supply are changed; omitted fields keep their current values. If no fields are supplied the function is a no-op.

Requirements

social_meta() must be present in the UI for the JavaScript handler to be registered. update_meta() alone has no effect.

Example

server <- function(input, output, session) {
  observeEvent(input$tabs, {
    if (input$tabs == "about") {
      shinyseo::update_meta(session,
        title       = "About – My App",
        description = "Learn more about the team behind the app."
      )
    }
  })
}

Behavior notes

  • The function does not mutate the input list outside its local copy.
  • The helper returns plain Shiny tags, so it is safe to embed in fluidPage(), navbarPage(), or any other UI container that accepts head tags.
  • The package is intentionally small and generic.
  • If you need a simpler SEO-only configuration, you can still use the required four fields and leave the rest blank.