---
title: "API Contract"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{API Contract}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

# API Contract for `shinyseo`

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

## Exported surface

- `social_meta(meta)`

There are no other exported helpers.

## Return value

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

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

```r
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 |

## 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.
