🔮 Sanity Create is here. Writing is reinvented. Try now, no developer setup

Stega-encoding

Learn about Stega, an encoding method for embedding metadata in apps, enabling click-to-edit features in Sanity's Visual Editing tools.

Stega (from “stenography) is an encoding method developed by Sanity in collaboration with Vercel that allows metadata mappings to be embedded into an application. It encodes Content Source Maps, a standard for annotating fragments in a JSON document with metadata about their origin.

With Stega enabled, data rendered in your application looks the same but contains invisible metadata that Sanity's Visual Editing tooling can detect. This enables click-to-edit overlays directly in your application without requiring you to manually set up mapping for components.

Gotcha

Stega encoding adds additional data to your strings in preview mode. The trade-off is that if you use these strings in business logic, your application might act differently in preview mode. You can use helper functions to clean out Stega-encoding before passing them to non-component contexts.

How Stega works

Stega-encoding takes the Content Source Maps JSON and encodes it into invisible UTF-8 encoded characters that are appended to a string value. The Visual Editing tooling can pick this up, decode it, and use for the click-to-edit functionality:

Oxford Shoes​​​​‌‍​‍​‍‌‍‌​‍‌‍‍‌‌‍‌‌‍‍‌‌‍‍​‍​‍​‍‍​‍​‍‌​‌‍​‌‌‍‍‌‍‍‌‌‌​‌‍‌​‍‍‌‍‍‌‌‍​‍​‍​‍​​‍​‍‌‍‍​‌​‍‌‍‌‌‌‍‌‍​‍​‍​‍‍​‍​‍‌‍‍​‌‌​‌‌​‌​​‌​​‍‍​‍​‍‌‌‍‌‍‍‌‌​‌‌‌‌‍​‌‌‍​​‍‌‌‍‌‌‌‍‌​‌‍‍‌‌‌​‌‍‍‌‌‍‍‌‍‌​‍‌‌​‌‌​‌‌‌‌‍‌​‌‍‍‌‌‍​‍‍‌​‌‍​‌‌‍‍‌‍‍‌‌‌​‌‍‌​‍‍‌‍​‍‌‌‌‌‍‍‌‌‍​‌‍‌​​‍‌​‍‌‍‌‌‌‍‌‌‍‍‌‌‍​​‍‌‍‍‌‌‍‍‌‌​‌‍‌‌‌‍‍‌‌​​‍‌‍‌‌‌‍‌​‌‍‍‌‌‌​​‍‌‍‌‌‍‌‍‌​‌‍‌‌​‌‌​​‌​‍‌‍‌‌‌​‌‍‌‌‌‍‍‌‌​‌‍​‌‌‌​‌‍‍‌‌‍‌‍‍​‍‌‍‍‌‌‍‌​​‌‌‍​‍​‍‌​‌‌​‌‍‌‍​‌‍‌‍​‌‌‍​‍​‍‌‌‍​‌​‌‌‍​‍​‌​‍‌​‌​‌‍‌‌​‌‌​‌‍​‍‌‌‍​‌​​‌​‌‍‌‍‌‍​‍‌‌‍​‍‌‍​‌‌‍‌​​‍​‌‍‌‌‌‍‌‌​​​‍‌​​‍‌‍‌‌​​​‌​​‍‌‌​‌‍‌‌​​‌‍‌‌​‌‌​‌‍‍​‌‍‌‍‌‌​‍‌​​‌‍​‌‌‌​‌‍‍​​‌‌‌​‌‍‍‌‌‌​‌‍​‌‍‌‌​‍‌‌​‌‍‌‍‌‍​​‌‌​​‌​‍‌‍‌‌‌​‌‍‌‌‌‍‍‌‌​‌‍​‌‌‌​‌‍‍‌‌‍‌‍‍​‌‍​‍‌‍​‌‌​‌‍‌‌‌‌‌‌‌​‍‌‍​​‌‌‍‍​‌‌​‌‌​‌​​‌​​‍‌‌​​‌​​‌​‍‌‌​​‍‌​‌‍​‍‌‌​​‍‌​‌‍‌‌‍‌‍‍‌‌​‌‌‌‌‍​‌‌‍​​‍‌‌‍‌‌‌‍‌​‌‍‍‌‌‌​‌‍‍‌‌‍‍‌‍‌​‍‌‌​‌‌​‌‌‌‌‍‌​‌‍‍‌‌‍​‍‍‌​‌‍​‌‌‍‍‌‍‍‌‌‌​‌‍‌​‍‍‌‍​‍‌‌‌‌‍‍‌‌‍​‌‍‌​​‍‌‍‌‍‍‌‌‍‌​​‌‌‍​‍​‍‌​‌‌​‌‍‌‍​‌‍‌‍​‌‌‍​‍​‍‌‌‍​‌​‌‌‍​‍​‌​‍‌​‌​‌‍‌‌​‌‌​‌‍​‍‌‌‍​‌​​‌​‌‍‌‍‌‍​‍‌‌‍​‍‌‍​‌‌‍‌​​‍​‌‍‌‌‌‍‌‌​​​‍‌​​‍‌‍‌‌​​​‌​​‍‌‍‌‌​‌‍‌‌​​‌‍‌‌​‌‌​‌‍‍​‌‍‌‍‌‌​‍‌‍‌​​‌‍​‌‌‌​‌‍‍​​‌‌‌​‌‍‍‌‌‌​‌‍​‌‍‌‌​‍‌‍‌‌‌‍‌​‍‌‍‍‌​‌​​‌‍​‌‌‍​‌‍‌‌​‌‌​‍‌‍‌‌‌‍‌‌‍‍‌‌‍​​‍‌‍‌‌​‌‍‌‍‌‍​​‌‌​​‌​‍‌‍‌‌‌​‌‍‌‌‌‍‍‌‌​‌‍​‌‌‌​‌‍‍‌‌‍‌‍‍​‍‌‍‌‍‍‌‌​‌​‌​‌​‍‌‍​‌‌‍‌‍‌‌​​‌​‍​‍‌‌

What is Content Source Maps?

Content Source Maps is a standard representation for annotating fragments in a JSON document with metadata about their origin: the field, document, and dataset they originated from. It provides a separate document alongside the content that adds the metadata without changing the original document's layout.

Content Source Maps enable annotating JSON documents with "source" metadata, allowing end users to navigate directly to the source to edit it. In the future, they will also enable the annotation of JSON documents with arbitrary metadata for other use cases.

The Content Source Map offers a standard method for representing the mapping between content values and their sources. Here is an example Content Source Map:

{
  "documents": [
    {
      "_id": "author-1"
    },
    {
      "_id": "author-2"
    }
  ],
  "paths": ["$['name']"],
  "mappings": {
    "$[0]": {
      "type": "value",
      "source": {
        "type": "documentValue",
        "document": 0,
        "path": 0
      }
    },
    "$[1]": {
      "type": "value",
      "source": {
        "type": "documentValue",
        "document": 1,
        "path": 0
      }
    }
  }
}

Troubleshooting

There are weird characters in your DOM

These are most probably the Stega encoded strings! They are a subset of HTML entities that, when rendered, produce invisible output. Below is the string value of “Oxford Shoes” when it contains a Stega-encoded Content Source Map:

Oxford Shoes​​​​‌‍​‍​‍‌‍‌​‍‌‍‍‌‌‍‌‌‍‍‌‌‍‍​‍​‍​‍‍​‍​‍‌​‌‍​‌‌‍‍‌‍‍‌‌‌​‌‍‌​‍‍‌‍‍‌‌‍​‍​‍​‍​​‍​‍‌‍‍​‌​‍‌‍‌‌‌‍‌‍​‍​‍​‍‍​‍​‍‌‍‍​‌‌​‌‌​‌​​‌​​‍‍​‍​‍‌‌‍‌‍‍‌‌​‌‌‌‌‍​‌‌‍​​‍‌‌‍‌‌‌‍‌​‌‍‍‌‌‌​‌‍‍‌‌‍‍‌‍‌​‍‌‌​‌‌​‌‌‌‌‍‌​‌‍‍‌‌‍​‍‍‌​‌‍​‌‌‍‍‌‍‍‌‌‌​‌‍‌​‍‍‌‍​‍‌‌‌‌‍‍‌‌‍​‌‍‌​​‍‌​‍‌‍‌‌‌‍‌‌‍‍‌‌‍​​‍‌‍‍‌‌‍‍‌‌​‌‍‌‌‌‍‍‌‌​​‍‌‍‌‌‌‍‌​‌‍‍‌‌‌​​‍‌‍‌‌‍‌‍‌​‌‍‌‌​‌‌​​‌​‍‌‍‌‌‌​‌‍‌‌‌‍‍‌‌​‌‍​‌‌‌​‌‍‍‌‌‍‌‍‍​‍‌‍‍‌‌‍‌​​‌‌‍​‍​‍‌​‌‌​‌‍‌‍​‌‍‌‍​‌‌‍​‍​‍‌‌‍​‌​‌‌‍​‍​‌​‍‌​‌​‌‍‌‌​‌‌​‌‍​‍‌‌‍​‌​​‌​‌‍‌‍‌‍​‍‌‌‍​‍‌‍​‌‌‍‌​​‍​‌‍‌‌‌‍‌‌​​​‍‌​​‍‌‍‌‌​​​‌​​‍‌‌​‌‍‌‌​​‌‍‌‌​‌‌​‌‍‍​‌‍‌‍‌‌​‍‌​​‌‍​‌‌‌​‌‍‍​​‌‌‌​‌‍‍‌‌‌​‌‍​‌‍‌‌​‍‌‌​‌‍‌‍‌‍​​‌‌​​‌​‍‌‍‌‌‌​‌‍‌‌‌‍‍‌‌​‌‍​‌‌‌​‌‍‍‌‌‍‌‍‍​‌‍​‍‌‍​‌‌​‌‍‌‌‌‌‌‌‌​‍‌‍​​‌‌‍‍​‌‌​‌‌​‌​​‌​​‍‌‌​​‌​​‌​‍‌‌​​‍‌​‌‍​‍‌‌​​‍‌​‌‍‌‌‍‌‍‍‌‌​‌‌‌‌‍​‌‌‍​​‍‌‌‍‌‌‌‍‌​‌‍‍‌‌‌​‌‍‍‌‌‍‍‌‍‌​‍‌‌​‌‌​‌‌‌‌‍‌​‌‍‍‌‌‍​‍‍‌​‌‍​‌‌‍‍‌‍‍‌‌‌​‌‍‌​‍‍‌‍​‍‌‌‌‌‍‍‌‌‍​‌‍‌​​‍‌‍‌‍‍‌‌‍‌​​‌‌‍​‍​‍‌​‌‌​‌‍‌‍​‌‍‌‍​‌‌‍​‍​‍‌‌‍​‌​‌‌‍​‍​‌​‍‌​‌​‌‍‌‌​‌‌​‌‍​‍‌‌‍​‌​​‌​‌‍‌‍‌‍​‍‌‌‍​‍‌‍​‌‌‍‌​​‍​‌‍‌‌‌‍‌‌​​​‍‌​​‍‌‍‌‌​​​‌​​‍‌‍‌‌​‌‍‌‌​​‌‍‌‌​‌‌​‌‍‍​‌‍‌‍‌‌​‍‌‍‌​​‌‍​‌‌‌​‌‍‍​​‌‌‌​‌‍‍‌‌‌​‌‍​‌‍‌‌​‍‌‍‌‌‌‍‌​‍‌‍‍‌​‌​​‌‍​‌‌‍​‌‍‌‌​‌‌​‍‌‍‌‌‌‍‌‌‍‍‌‌‍​​‍‌‍‌‌​‌‍‌‍‌‍​​‌‌​​‌​‍‌‍‌‌‌​‌‍‌‌‌‍‍‌‌​‌‍​‌‌‌​‌‍‍‌‌‍‌‍‍​‍‌‍‌‍‍‌‌​‌​‌​‌​‍‌‍​‌‌‍‌‍‌‌​​‌​‍​‍‌‌

When rendered in an HTML document, this string will still display as “Oxford Shoes.” You use this tool to test the string by pasting the value above into the “Encoded” input field.

Comparing field values doesn’t work in preview mode

Your application likely evaluates values from the Content Lake to perform specific logic. If these values contain invisible encoded metadata, they may no longer work.

For example, imagine a function that determines that a Sanity document's market value is the same as the current market:

function showDocument(document: SanityDocument, currentMarket: string) {
  return document.market === currentMarket
}

Without stega enabled, this function works as expected. However, if document.market contains encoded metadata, this comparison will fail.

If document.market is never shown on the page and will not benefit from Visual Editing, removing it from the encoded paths in encodeSourceMapAtPath may be best.

Alternatively, clean the value before comparing it:

import {vercelStegaCleanAll} from "@sanity/client/stega"

function showDocument(document: SanityDocument, currentMarket: string) {
  return vercelStegaCleanAll(document.market) === currentMarket
}

Since you'll likely do this more than once, consider extracting to a helper function.

Was this article helpful?