Reference Guide

Reference for shinyseo

This package generates metadata for a Shiny app and returns HTML tags for <head>.

It is useful when you want the page to look right in shares on Facebook, LinkedIn, X, Slack, and other services that read Open Graph or Twitter Card metadata.

Main flow

  1. Pass a YAML file or a named list to social_meta() in the UI.
  2. social_meta() reads the data, fills in defaults, validates required fields, and builds a tags$head() block with metadata and a JavaScript handler.
  3. Optionally call update_meta() in the server to update one or more fields reactively without a page reload.

Inputs

social_meta(meta) accepts:

  • a string containing a path to YAML
  • or a named list

Required fields

These must always exist:

  • title
  • description
  • url
  • image

If one is missing, the function stops with an error.

Defaults

If you do not set them yourself, these defaults are used:

  • 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

What tags are created

The function builds:

  • <link rel="canonical">
  • meta name="description"
  • meta name="robots"
  • meta property="og:*"
  • meta name="twitter:*"
  • meta name="msvalidate.01" when Bing verification is set or when SHINYSEO_BING_SITE_VERIFICATION is present
  • meta name="google-site-verification" when Google verification is set
  • meta name="yandex-verification" when Yandex verification is set
  • meta name="baidu-site-verification" when Baidu verification is set
  • meta name="naver-site-verification" when Naver verification is set
  • meta name="facebook-domain-verification" when Facebook domain verification is set
  • meta name="p:domain_verify" when Pinterest domain verification is set
  • <script type="application/ld+json"> for schema.org
  • no <title> tag; set the title in the app UI instead

Open Graph

These fields are used directly in Open Graph:

  • title
  • description
  • url
  • image
  • site_name
  • locale
  • image_width
  • image_height
  • image_type
  • image_alt

Twitter Card

These fields are used directly in Twitter Card:

  • twitter_card
  • twitter_site with fallback to SHINYSEO_TWITTER_SITE
  • twitter_creator with fallback to SHINYSEO_TWITTER_CREATOR
  • twitter_image_alt

Bing verification

Bing verification is used directly when the following is set:

  • bing_site_verification

If that field is missing, SHINYSEO_BING_SITE_VERIFICATION is used when present.

Schema.org JSON-LD

JSON-LD is created with these base fields:

  • @context = "https://schema.org"
  • @type = schema_type
  • name = title
  • description = description
  • url = url
  • inLanguage = in_language

Additional fields may be included:

  • application_category
  • operating_system
  • educational_use
  • is_accessible_for_free
  • disclaimer
  • author_name
  • publisher_name

If you set schema = FALSE, JSON-LD is omitted entirely.

Custom meta tags

The custom field accepts a list of lists. Each inner list becomes one <meta> tag; its names map directly to HTML attributes.

custom = list(
  list(name     = "viewport",  content = "width=device-width, initial-scale=1"),
  list(property = "og:video",  content = "https://example.no/video.mp4"),
  list(name     = "x-app-env", content = "production")
)

Use name for standard meta tags and property for Open Graph-style tags. Any other valid HTML attribute is also accepted.

Practical example

ui <- shiny::fluidPage(
  shinyseo::social_meta(list(
    title = "Calculator",
    description = "A simple app for calculating things.",
    url = "https://example.no",
    image = "https://example.no/preview.png",
    twitter_site = "@example",
    twitter_creator = "@example",
    schema = TRUE
  )),
  shiny::h1("Calculator")
)

Favicon and web app manifest

Add favicon and PWA support by setting optional fields in the same metadata object:

# global.R
shinyseo::write_manifest(list(
  title            = "My App",
  short_name       = "MyApp",
  description      = "A Shiny web app.",
  theme_color      = "#1a73e8",
  favicon          = "/favicon.svg",
  favicon_png      = "/favicon-32.png",
  apple_touch_icon = "/apple-touch-icon.png"
))
# ui.R
shinyseo::social_meta(list(
  title            = "My App",
  description      = "A Shiny web app.",
  url              = "https://example.no",
  image            = "https://example.no/share.png",
  favicon          = "/favicon.svg",
  favicon_png      = "/favicon-32.png",
  apple_touch_icon = "/apple-touch-icon.png",
  theme_color      = "#1a73e8",
  manifest         = "/manifest.json"
))

Place the icon files in the www/ folder of the app. write_manifest() writes www/manifest.json automatically.

The MIME type for favicon is inferred from the file extension. Supported: .ico, .png, .svg, .webp, .gif. Override with favicon_type if needed.

SVG favicons need a PNG fallback

If favicon is an SVG, also set favicon_png (optionally with favicon_png_sizes, default "32x32"). Chromium-based browsers (Chrome, Edge, Comet, etc.) don’t render SVG favicons in the address bar – without a PNG fallback the address bar shows a generic globe icon even though the browser tab displays the SVG correctly. write_manifest() also includes favicon_png in the generated manifest.json icons.

Reactive metadata with update_meta()

Call update_meta() in the server when the visible content changes — for example when the user switches tabs or navigates between routes. Only the fields you supply are updated; everything else stays as set by social_meta().

ui <- shiny::navbarPage("My App",
  shinyseo::social_meta(list(
    title       = "My App",
    description = "A multi-tab Shiny app.",
    url         = "https://example.no",
    image       = "https://example.no/preview.png"
  )),
  shiny::tabPanel("Home"),
  shiny::tabPanel("About")
)

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."
      )
    } else {
      shinyseo::update_meta(session,
        title       = "My App",
        description = "A multi-tab Shiny app."
      )
    }
  })
}

social_meta() must be present in the UI for the JavaScript handler to be registered.

When to use it

Use the package when you want a small, tidy metadata solution in a Shiny app without building a custom metadata engine.

It is especially useful when you:

  • have one app or a small number of apps
  • want to manage metadata from a YAML file
  • want the same metadata across multiple environments
  • want social sharing and search results to behave predictably
  • have tabbed or multi-route apps where metadata should reflect the current view