> ## Documentation Index
> Fetch the complete documentation index at: https://metamanager.dev/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Changelog

> What changed, and when.

<Update label="v1.18" description="Edit a customer brand from the dashboard">
  **Brands can be added and edited under Signed cards**, including a logo. Set
  `mark_source` to an image address and we fetch it once and keep it, so drawing
  a card never waits on your customer's server.

  Also fixed: a customer already on a paid plan saw the pricing page mark their
  card as theirs while the button still invited them to buy it. It now opens the
  billing portal, on every paid plan rather than only Pro.
</Update>

<Update label="v1.17" description="Signed cards no longer need a registered brand">
  **Colours and a picture can travel in the signed payload.** Send `bg`, `fg`,
  `ac` and `i` and the card draws in those colours with that image, having
  registered nothing.

  Registering a brand still earns its place for one thing a URL cannot do: carry
  a **logo**. A mark is image data rather than an address, so it is resolved once
  when you save it and stored — drawing must not need the network. Brands
  are also handy if you would rather not repeat the same fields on every page.

  Where both exist, the payload wins: it is the most specific and the most
  current.
</Update>

<Update label="v1.16" description="Photographic cards got fourteen times smaller">
  **A card with a photograph on it now comes back as JPEG rather than PNG.** The
  same card went from 896 KB to 64 KB — and 896 KB was past the size our own
  checker flags as a preview image too heavy, so we were shipping cards
  MetaManager would have complained about.

  Cards without a photograph are still PNG, which is smaller for flat colour.
  The format follows the content.

  **The image limit is now 4 MB, up from 1 MB.** One megabyte was a guess and it
  was wrong: an ordinary unoptimised stock photo is two to three, so the first
  real image anybody tried was quietly refused. When an image still cannot be
  used, the reason is now shown — too large, not an image, unreachable
  — instead of the card simply appearing without it.
</Update>

<Update label="v1.15" description="Your own image on the card">
  **A fifth layout, `banner`, draws a picture behind your words.** Point `&i=` at
  the image you want:

  ```html theme={null}
  <meta property="og:image"
        content="https://og.metamanager.dev/card?k=pk_...&u={{ current_url }}&tpl=banner&i={{ hero_image_url }}">
  ```

  Explicit on purpose. We do not scan your page for a likely-looking image,
  because the first one on a page is a logo or a tracking pixel about as often as
  it is the picture you meant, and guessing wrong puts a broken card on a live
  page.

  Fetched once and cached with the card, so it is one request per page per day
  rather than one per share. If it cannot be fetched, the card draws without it.
</Update>

<Update label="v1.14" description="Adjust a layout without leaving the built-ins">
  **Four settings on every card layout:** title size, alignment, whether the
  description draws, and whether your mark appears. Set them once in your
  account, or override one on a single page with `&ts=l`, `&align=center`,
  `&desc=0` or `&mark=0`.

  These deliberately stop short of a template editor. Each one changes *how* a
  card is drawn and none can change *what* it says — no setting can add
  text, an image or a link. That is what lets them ship without the review a
  free-form editor would need before anything drawn on our domain could appear
  as a preview for somebody else's page.
</Update>

<Update label="v1.13" description="Cards for your customers' domains">
  **A new Business plan, for platforms that draw cards on behalf of their own
  customers.** Instead of verifying every customer domain — which does not scale
  and cannot cope with a domain added this afternoon — you sign each card on your
  server, and the signature authorises it.

  Because the payload carries the title, we never fetch the page: cards draw for
  pages behind a login or not yet published, and they cache permanently, since a
  changed title is a changed signature is a changed URL.

  Each of your customers can have their own colours, mark and layout, registered
  once and referenced by id. Otherwise all of them would wear yours.

  [Cards for your customers →](/docs/guides/og-cards-for-saas)
</Update>

<Update label="v1.12" description="Choose the language a page is read in">
  **Add `&l=` to a card URL to say which language to read the page in.**

  ```html theme={null}
  <meta property="og:image"
        content="https://og.metamanager.dev/card?k=pk_...&u={{ current_url }}&l=de">
  ```

  Without it, a site that varies by locale serves whichever language our edge
  happens to prefer — which is how a card for a US pricing page came back in
  Dutch. We deliberately send no language by default rather than assuming
  English, because a default would quietly change what we report for every site
  that honours the header.

  This chooses the language we **read** in, not the one we draw in. Which
  typeface a card uses is decided from the text we actually get back, so a page
  tagged `en` that is full of Japanese still renders correctly.

  Related: cards now also read a page's own `lang` attribute to tell Traditional
  and Simplified Chinese apart. Most Chinese characters are shared between the
  two, so the page is the only thing that can say which forms to draw.
</Update>

<Update label="v1.11" description="Four card layouts">
  **Cards can now use one of four layouts**, chosen under **Social cards** in
  your account:

  * **Classic** — title and description, with your mark above. The default, and
    unchanged: existing cards draw exactly as they did before.
  * **Minimal** — the title alone, set large.
  * **Split** — an accent panel beside the text. The panel's text colour is
    computed from your accent so it stays readable whatever you pick.
  * **Quote** — sets the description as a pull quote. Good for writing, less so
    for a pricing page.

  Pick a default in the dashboard, or override it per page by adding
  `&tpl=minimal` to the card URL — so one template can serve your blog and
  another your product pages, from the same key.

  An unrecognised name falls back to your saved default rather than failing.
  Nothing on this service returns an error where it could return a card.
</Update>

<Update label="v1.10" description="Social cards in your own script">
  **Cards now draw in Japanese, Chinese, Korean, Cyrillic and Greek.** Until now
  the renderer shipped a Latin-only face, so a Japanese or Russian page got a
  card full of empty boxes — and got it with a confident `200`, which is the
  worst way to be wrong.

  * Faces are chosen from the text itself, not from the page's language tag, so
    an English-tagged page full of Japanese still draws correctly.
  * Traditional and Simplified Chinese are told apart by the page's own `lang`,
    since most Han characters are shared and the text alone cannot decide.

  **Some scripts are deliberately declined.** Arabic, Hebrew and the Indic
  scripts are drawn as a plain card showing the page's address instead of its
  title. That is not an oversight and it is not about fonts: our renderer lays
  words out left to right and does not reshape them, so Arabic would come out
  with each word correct and *the sentence in reverse reading order* — a card
  that looks right and reads backwards. We would rather show less than show
  something untrue about your page.

  Cards that fall back this way carry an `x-mm-degraded` header saying why.
</Update>

<Update label="v1.9" description="Generated social cards">
  **One line in your template gives every page a link preview image.** The card
  is drawn from that page's own title and description, in colours you choose,
  with your site's icon as the mark.

  ```html theme={null}
  <meta property="og:image"
        content="https://og.metamanager.dev/card?k=pk_...&u={{ current_url }}">
  ```

  * No backend code and nothing to sign. The key in the URL is public by design;
    a card is only drawn for a **domain you have verified**, so a copied key is
    useless to whoever copies it.
  * Content comes from the page itself, through the same checker you already
    use — so the card cannot drift out of step with what it previews.
  * A page with no title still gets a card, drawn from its URL. This runs inside
    your page, and an error there is a broken preview across every platform.

  Free draws **100 cards a month** and marks them; Pro draws **5,000** and does
  not. Cards are counted when drawn, not when a link is shared — a page shared a
  thousand times costs one card, redrawn about daily so an edited title appears
  on its own.

  You can see one drawn before signing up — the [home page](https://metamanager.dev/#cards)
  takes any URL and returns a card for it. Demo cards use our colours and carry
  our mark; yours use yours, and do not.
</Update>

<Update label="v1.8" description="A check for heavy social images">
  **New issue code: `og_image_too_heavy`.** Every service that unfurls your link
  refetches your `og:image`, and a 1200 by 630 preview usually compresses to well
  under 500 KB. Nothing rejects a larger one — the platform limits are several
  megabytes — so this is a tip, raised only when the image was actually fetched
  and measured.

  It carries **no score impact**, deliberately. The score is earned over
  applicable weight, so a weighted rule would change the denominator and move
  every historical score at once — which audit comparison would report as a
  change on every page, and monitoring would email about. A new observation must
  not rewrite old measurements.
</Update>

<Update label="v1.7" description="API keys and an MCP server">
  **Your agent can now drive MetaManager.** A remote MCP server at
  `mcp.metamanager.dev` gives an AI agent tools to check a page, read its issues,
  apply a fix, and re-check to confirm the score moved.

  * Create an API key at your account and send it as a bearer token; the whole
    `/api` surface works without a cookie.
  * Keys are **read-only** unless you give them write access, because starting an
    audit spends a monthly allowance and an agent in a loop will not notice.
  * The key is shown once. Only a hash is stored, so it cannot be recovered —
    revoke and create another instead.
  * Every key on an account shares one hourly bucket. Ten keys are not ten times
    the quota.
  * A **Free** key is real: single-page checks, fix prompts and the issue
    catalogue, at Free's 100 an hour. The heavier tools say they need Pro.

  **AI metadata suggestions have been dropped**, not postponed. The fix prompt
  already hands your own assistant everything it needs, and generating copy
  ourselves would have added cost and put a prompt-injection surface behind our
  own key — the pages we read are written by the people we would be reading them
  for. Letting your agent use MetaManager is the better shape.
</Update>

<Update label="v1.6" description="Shareable reports and PDF export">
  **Hand an audit to somebody who does not have an account.** Open a finished
  audit, choose **Share**, and publish a read-only copy at a public link.

  * The link works until you revoke it, and revoking takes effect immediately.
  * Sharing the same audit twice returns the same link rather than a second one,
    so a link can always be found again — and always withdrawn.
  * The panel shows how many times the link has been opened.
  * Shared reports are served `noindex`; the link itself is the secret.

  Free publishes a **summary** — site, date, score and issue categories. Pro adds
  the page-by-page breakdown. The limit follows the account rather than the
  link, so upgrading widens a link you have already sent.

  **Pro can export to PDF**, from the dashboard or from the shared page, without
  publishing a link first. The PDF is the report rather than a second rendering
  of it: same numbers, navigation removed, page breaks placed so a table does not
  split mid-row, and every affected URL printed in full.
</Update>

<Update label="v1.5" description="Audit comparison and alert recipients">
  **See what changed between two audits.** Open a finished audit and choose
  **What changed** to compare it with the previous run of the same site: new
  issues, fixed issues, changed tags with their before and after, pages that
  appeared, and pages that are gone.

  * Compares against the most recent finished audit of the same site, so a
    manual run and a scheduled one can be compared with each other.
  * Audits crawled before metadata capture existed cannot be diffed tag by tag.
    Rather than reporting every tag as changed, the comparison says so and still
    reports issue and page changes, which remain accurate.

  **Alerts can go somewhere other than the account holder.** Each monitor takes
  its own recipient, confirmed by a link valid for 24 hours. Until it is
  confirmed, alerts keep going to the account holder.

  **Projects now scope the whole dashboard.** A project holds a site's saved
  URLs, its audits and its monitors, and the sidebar switcher applies that scope
  across every page. Anything filed nowhere is reachable under **Unfiled**.
</Update>

<Update label="v1.4" description="Scheduled monitoring">
  **Watch a site and get an email when its metadata breaks.** Pro watches up to
  three sites, daily or weekly. Scheduled runs are checked every 15 minutes and
  do not spend the monthly audit allowance.

  * Seven fields are watched per page: `title`, `description`, `canonical`,
    `og:title`, `og:description`, `og:image` and `twitter:card`.
  * Whitespace is normalised before comparison, so a deploy that reflows
    templates is not a change.
  * You are emailed for new issues and for pages that have vanished — not for a
    reworded description. A site that stays broken produces one email, not one
    per run.
  * The first run of a monitor never emails: there is nothing to compare it to.
</Update>

<Update label="v1.3" description="Site audits">
  **Crawl a whole site rather than one page.** Free audits 25 pages once a
  month; Pro audits 500 pages, 50 times a month. Audits are metered separately
  from the hourly check quota, so one large crawl cannot exhaust it.

  * `robots.txt` is fetched first and obeyed, including `Crawl-delay`, with
    longest-match precedence and `Allow` winning ties.
  * One request at a time per audit, with a delay between them, backing off when
    a server struggles.
  * Same origin as the root URL only, and every discovered URL passes the same
    validation that protects `GET /inspect` — a crawler that trusted `href`
    values would be an SSRF engine.
  * The site score is the unweighted mean of page scores, reported alongside the
    three buckets, because the distribution is what a mean hides.
  * The bot identifies itself as `MetaManagerBot/1.0` and
    [explains itself](https://metamanager.dev/bot).
</Update>

<Update label="v1.2" description="Pro plans">
  **Subscriptions, monthly or yearly, through Polar.** Entitlements are resolved
  from the account rather than the session, so a plan change takes effect on the
  next request.

  Pro raises checks to 1,000 an hour and makes saved URLs and projects
  unlimited. Everyone keeps the free checker.
</Update>

<Update label="v1.1" description="Accounts, saved URLs and projects">
  **Sign in with an emailed link — no password to choose, store or leak.**

  * Save URLs and re-check them from the dashboard: three on Free, unlimited on
    Pro.
  * Group them into projects: one on Free, unlimited on Pro.
  * Signed-in Free accounts get 100 checks an hour, up from the 50 available
    without an account.
</Update>

<Update label="v1.0" description="The free checker">
  **`GET /inspect`** — metadata extraction, a weighted 0–100 score, previews for
  eight platforms, and 31 issue codes with paste-ready fixes.

  * Character references are decoded, so `Ben &amp;amp; Jerry&amp;#39;s` reports as
    `Ben & Jerry's` and length rules count what a reader sees.
  * Social images are fetched and measured from their own header bytes, which is
    what makes `image_dimensions_mismatch` detectable.
  * Non-2xx pages return a structured error rather than being scored as empty
    documents.
  * `prompt=` produces a paste-ready AI fix prompt for HTML, Laravel, Next.js,
    Nuxt or a framework-agnostic form. Derived after the cache, so switching
    framework costs nothing.
  * `GET /entitlements` reports the caller's plan and limits.
</Update>
