llms.txt

Farcaster Snaps

Snaps are interactive embeds inside Farcaster casts. They render as cards in the feed and can be multi-page, stateful, and dynamic.

Using Claude Code? Install the snap generator skill and run /create-farcaster-snap to go from prompt to deployed snap. See the Building a Snap guide for install instructions and all other approaches.

Overview

A Farcaster Snap is defined by a JSON schema served by an external server. The Farcaster client renders the JSON -- it never executes arbitrary code.

Snaps are the evolution of Frames: richer elements, multi-page flows, dynamic content, and the same server-driven model.

How It Works

  1. A cast embed points to a URL that implements the Snap protocol
  2. The client GETs that URL, signaling snap support. The server responds with a JSON SnapResponse
  3. The client renders the response as an embed
  4. The user interacts (taps a button, moves a slider, types text)
  5. The client POSTs the interaction data to the server and receives a new JSON SnapResponse
  6. The client replaces the previous content with the new content
  7. Repeat

Signaling Snap Support

The snap media type is application/vnd.farcaster.snap+json.

  • A client MAY include application/vnd.farcaster.snap+json in Accept to indicate snap support
  • If application/vnd.farcaster.snap+json is the highest-priority acceptable type, the server MAY return a snap response
  • If the server returns a snap response, it MUST set Content-Type: application/vnd.farcaster.snap+json
  • If the request does not indicate snap support, the server SHOULD return a normal HTTP response (for example, a fallback or guidance)
  • Even when snap is requested, the server MAY return a different content type

If the response Content-Type is application/vnd.farcaster.snap+json, the client MUST render it as a snap.

Clients MAY cache GET responses from snap servers to avoid extraneous re-fetching.

SnapResponse Shape

Every valid response is a page payload with this shape:

{
  "version": "1.0",
  "page": {
    "theme": {
      "accent": "purple"
    },
    "elements": {
      "type": "stack",
      "children": [
        { "type": "text", "style": "title", "content": "Hello world" }
      ]
    },
    "buttons": [
      {
        "label": "Submit",
        "action": "post",
        "target": "https://example.com/submit"
      }
    ]
  }
}

Top-Level Fields

FieldRequiredDescription
versionYesSpec version. Must be "1.0"
page.themeNoAccent color for the snap. Client derives all visual styling from this + the app's current light/dark mode. Defaults to "purple"
page.elementsYesPage body tree root. MUST be { "type": "stack", "children": [...] }. Min 1, max 5 children. Max 1 media element
page.buttonsNoArray of action buttons at the bottom. Min 0, max 4
page.button_layoutNoLayout for action buttons: "stack" (default), "row", "grid"
page.effectsNoArray of effect names to trigger on page load

Feed Card Dimensions

  • Width: 100% of the feed column. The client determines the actual pixel width
  • Height: Determined by content, designed so valid pages fit within a ~500px feed card

All snap pages render in the feed card -- including pages returned by post button taps. The card replaces its content in place.

There is no client-managed back button. Navigation is server-driven.

If a snap wants "go back" functionality, it includes a button on the page that POSTs to the server, and the server returns the appropriate previous page. The server is responsible for maintaining navigation state.

Linking Between Snaps

A button with action: "post" can target any snap server URL, including a different snap's URL. This allows one snap to link to another.

When the user taps such a button, the client fetches the target URL, receives a page JSON, and renders it. The user is now "inside" the new snap.

Broken Snaps

If the snap URL is unreachable, returns invalid JSON, or fails schema validation:

  • The embed does not render in the feed
  • The cast displays normally with the snap URL shown as plain text
  • The client may cache the last valid first page and show it with a "stale" indicator

If a post button request fails (timeout, server error, or invalid JSON response):

  • The client stays on the current page -- it is never replaced with a blank screen
  • An inline error is shown: "Something went wrong. Tap to retry."
  • The user can retry the same button tap, or close/navigate away

Versioning

The version field is required on every page response. Clients must check this field.

  • If the version is supported, render normally
  • If the version is newer than the client supports, show a fallback: "Update Farcaster to view this snap"
  • Snaps should target the lowest version that supports their element types