Studio Docs

When to Use

Pin a Contentstack entry to a Freeform template via the Additional Entry Data section so components on that template can bind to the entry’s fields.

Use only on Freeform templates needing to bind components to a specific entry — “pin this entry”, “I can’t find my entry on this template”, “Pinned Entry missing from Data Picker”. Connected templates auto-bind via their content type so they don’t expose Additional Entry Data. Do NOT use on Connected templates; for dynamic lists use pin-query-to-freeform.

⛔ Auth preflight — settle the credential before the first API call. Resolve it OAuth-first per authenticate-cma: CS_OAUTH_ACCESS_TOKEN, else the Contentstack MCP’s stored session. Never ask the user for a session authtoken. If nothing resolves, or a refresh fails with 400 invalid_refresh_token, hand them ! CONTENTSTACK_REGION=<code> npx @contentstack/mcp --auth — it needs a TTY and a browser, so it cannot be run for them — and wait. 403 error_code 316 is a valid credential aimed at another org: fix the org or the api_key, do not re-authenticate.

Pin Entry to Freeform Template

Prerequisite: this skill assumes you’ve already chosen Freeform via choose-connected-vs-freeform. If you haven’t, run that first — Connected is the recommended default in Studio and most pages should use it (including one-off pages, via a single-entry CT). Freeform is the documented exception, not a parallel option. This skill remains valid for the legitimate Freeform cases; it just shouldn’t be your starting point.

Context

Freeform templates have no inherent connection to a content type, so by default their components have nothing to bind to beyond template.* exposed props and static values. The Additional Entry Data section on the template’s Data tab lets an author “pin” one or more Contentstack entries to the template; once pinned, every component on the template can bind props to that entry’s fields through the Data Picker under the Additional Entry Data → <title> root.

This is a Freeform-only flow. Connected templates auto-bind to a single entry via their connected content type, and the right panel does not render the Additional Entry Data section at all on a Connected template — you bind through Linked Template Entry instead.

A placed section is rooted, not bound field by field. The pinned-entry root above is for components authored directly on the template. A section dropped on the template resolves through its own per-placement Section Data row (right panel → Properties): root the placement at the pinned entry via the Entire Entry row, or at a field inside it, and the section’s internal bindings resolve against that document. The Section Data picker offers only targets whose structure matches what the section declared, so an incompatible entry simply doesn’t appear. Reference: docs/sections/binding-to-cms.md § Part 3 — Section Data.

Reference: docs/freeform/pinned-entries.md.

Mental model:

  • Pinned entries are a template-level resource. They live on the template, not on any single component.
  • They show up in the Data Picker as a binding root, alongside (not replacing) template.* exposed props, Component Default Data, and any Pinned Queries.
  • The Data tab is context-sensitive: with nothing selected it shows template-level config (Additional Entry Data, Pinned Queries); with a component selected it shows that component’s bindings. You must deselect to reach the pin UI.

Task

  1. Confirm the template is Freeform. Open templateName in Studio and look for the FREEFORM MODE badge on the canvas. If you see a Connected template indicator instead, stop — pinning does not apply; bind via Linked Template Entry.

  2. Verify Freeform is enabled at the project level. In project settings, confirm Enable Freeform Feature is on. Without it, the Data tab does not render at all and you’ll incorrectly conclude pinning is broken.

  3. Deselect any component on the canvas. Click an empty area of the canvas so no component is selected. If a component is selected, the Data tab swaps to component-level bindings and Additional Entry Data is not visible.

  4. Open the Data tab and expand Additional Entry Data. Right panel → Data tab → expand the Additional Entry Data accordion → click Link Entry.

  5. Pick the entry. In the entry picker modal:

    • Filter by content type using entryContentTypeUid.
    • Search by title using entrySearchTerm.
    • Select the matching entry.
    • Confirm.
  6. Verify the pin landed. The Additional Entry Data section should now list the pinned entry with its title and content type label. It will remain visible whenever the template is loaded with no component selected.

  7. Bind a component prop to a pinned-entry field. Select any component on the canvas, click the binding chip next to a prop in the right panel, and in the Data Picker navigate Additional Entry Data → <entry title> → <field>. Confirm. The canvas should re-render with the live field value.

  8. (Optional) Bindings inside a Repeater. If you bind a Repeater’s source to a reference field on the pinned entry, every reference inside that Repeater — single-CT or multi-CT — needs a Condition Block before its fields are reachable. Iteration-scoped bindings use repeater.<field>; template-level bindings continue to use template.<field>. Pinned-entry bindings appear as their own root and are neither.

Inputs Needed From the User

Collect in this order. If any is missing, ask before clicking anything in Studio.

  1. templateName — the Freeform template to pin onto.
  2. entryContentTypeUid — the content type UID to filter by in the picker.
  3. entrySearchTerm — title or UID to locate the specific entry.

Acceptance

This skill succeeds only when ALL of the following are true. If any fails, surface the failure and stop.

  • The template displays the FREEFORM MODE badge.
  • Enable Freeform Feature is on at the project level.
  • With nothing selected on the canvas, the right panel’s Data tab shows Additional Entry Data with the pinned entry listed (title + content type).
  • With a component selected, the Data Picker shows Additional Entry Data → <title> as a binding root.
  • A prop bound via Additional Entry Data → <entry title> → <field> renders the entry’s live value on the canvas — verified by inspecting a PNG screenshot of the canvas iframe (a11y snapshots are opaque to iframe contents).
  • Unpinning the entry removes the Pinned Entry root from every component’s Data Picker on that template.

Verifying the Runtime Render

If you want to confirm the pinned entry flows through at runtime (not just in Studio), the canvas-app side uses:

// SSR — fetchCompositionData THROWS on a miss (it does not resolve with
// hasSpec:false), so an unwrapped call 500s instead of 404ing. A compositionUid
// lookup throws COMPOSITION_NOT_FOUND (not ..._BY_URL). Wrap it:
// configure-csr-vs-ssr § "fetchCompositionData does not return not-found".
const { specOptions, notFound: miss } = await resolveComposition(sdk, {
  compositionUid: "<your-freeform-uid>",
});
if (miss) return notFound();
return <StudioComponent specOptions={specOptions} />;

The pinned entry data is embedded inside specOptions.spec — you do NOT pass it via the data prop. data is a separate Record<string, any> for runtime Component Default Data (external data outside Contentstack — live pricing, geo, etc.).

The Freeform composition URL only carries {{composition_uid}} plus {{environment}} and {{branch}} — it does not carry {{entry.*}} or {{content_type_uid}}. The pin is resolved server-side from the composition itself. ({{locale}} is accepted by the pattern engine but not recommended in URL patterns; carry locale via your routing layer + the SDK locale query option.)

Common Pitfalls

PitfallSymptomFix
Pinning attempted on a Connected templateNo Additional Entry Data section in the Data tabUse the Connected template’s Linked Template Entry binding root instead; this skill does not apply.
A component is selected while opening the Data tabData tab shows component bindings; no Additional Entry Data sectionClick empty canvas to deselect, then reopen the Data tab.
Enable Freeform Feature is off at the project levelData tab does not render at all on Freeform templatesToggle Enable Freeform Feature on in project settings.
Picker filter not set to entryContentTypeUidWrong / too many entries in the search listApply the content-type filter before searching by title.
Reference field inside a Repeater bound without a Condition BlockReference fields don’t appear in the Data Picker under the repeater iterationWrap the reference in a Condition Block (required for single-CT and multi-CT alike).
Section dropped on the template renders component defaultsPinning an entry does not bind a placed section — a section resolves through its own root, not the template’s binding rootsSelect the placement → Properties → Section Data → pick the pinned entry (Entire Entry) or a matching field inside it
Mixing iteration vs template scoperepeater.<field> used outside a Repeater, or template.<field> used for per-iteration dataUse repeater.<field> only inside a Repeater iteration; template.<field> only for template-level exposed props; Additional Entry Data → …` is its own root.

See Also