---
title: "Vercel Content Link"
aliases: [vercel-csm, content-source-maps, visual-editing-vercel]
tags: [payloadcms, vercel, visual-editing, integrations, enterprise]
sources: [raw/integrations__vercel-content-link.md]
created: 2026-05-15
updated: 2026-05-15
---

## Overview

Vercel Content Link lets editors click any rendered text on a Vercel preview and jump directly to the Payload field that controls it. Payload embeds **Content Source Maps** (invisible stega-encoded JSON) in API responses; Vercel's toolbar decodes them and highlights editable fields in blue.

**Enterprise-only** — requires `@payloadcms/plugin-csm` and an API key from Payload sales. Works only on Vercel-hosted deployments.

---

## Setup

### 1. Install plugin

```bash
npm i @payloadcms/plugin-csm
```

### 2. Register in Payload config

```ts
import contentSourceMaps from '@payloadcms/plugin-csm'

export default buildConfig({
  plugins: [
    contentSourceMaps({
      collections: ['pages'],   // opt-in per collection
    }),
  ],
})
```

### 3. Enable encoding in Next.js (draft/preview only)

**REST API:**
```ts
if (isDraftMode || process.env.VERCEL_ENV === 'preview') {
  const res = await fetch(
    `${process.env.NEXT_PUBLIC_PAYLOAD_CMS_URL}/api/pages?encodeSourceMaps=true&where[slug][equals]=${slug}`,
  )
}
```

**Local API:**
```ts
if (isDraftMode || process.env.VERCEL_ENV === 'preview') {
  const res = await payload.find({
    collection: 'pages',
    where: { slug: { equals: slug } },
    context: { encodeSourceMaps: true },
  })
}
```

> Only enable `encodeSourceMaps` in draft mode or preview deployments — it adds encoding overhead.

---

## Edit Mode

1. Visit any **preview deployment** on Vercel.
2. Log in via the **Vercel Toolbar**.
3. When CSMs are detected, a pencil icon appears → click to enter **Edit Mode**.
4. All editable fields are highlighted in blue with click-through links to Payload.

---

## Troubleshooting

### Date fields
Date fields are not encoded by default. If negative `letter-spacing` CSS causes rendering issues, split the encoded value:

```ts
import { vercelStegaSplit } from '@vercel/stega'
const { cleaned, encoded } = vercelStegaSplit(text)
// use `cleaned` for rendering, `encoded` carries the source map
```

### Blocks and array fields
`blocks` and `array` fields have no plain text to encode. They receive an `_encodedSourceMap` property instead. Use it to make entire sections clickable:

```tsx
<div data-vercel-edit-target>
  <span style={{ display: 'none' }}>{_encodedSourceMap}</span>
  {children}
</div>
```

---

## Key Takeaways

- **Enterprise only** — needs API key + `@payloadcms/plugin-csm`.
- Payload injects stega-encoded Content Source Maps into REST and Local API responses via the `encodeSourceMaps` flag.
- Only enable encoding in **draft mode / preview** to avoid production overhead.
- `date` fields are excluded from encoding by default — use `vercelStegaSplit` if needed.
- `blocks` / `array` fields get `_encodedSourceMap` property + `data-vercel-edit-target` for section-level editing.
- No changes required to frontend rendering code beyond adding `encodeSourceMaps=true` to queries.

---

## Related

- [[wiki/payloadcms/admin-preview|Admin Preview & Draft Preview]] — draft mode setup in Next.js
- [[wiki/payloadcms/live-preview|Live Preview]] — Payload's own iframe live preview (no Vercel required)
- [[wiki/payloadcms/plugins|Official Plugins]] — full plugin registry
- [[wiki/payloadcms/rest-api|REST API]] — query params reference
- [[wiki/payloadcms/local-api|Local API]] — `context` property usage

---

## Sources

- [Vercel Content Link — Payload Docs](https://payloadcms.com/docs/integrations/vercel-content-link)
- [`@vercel/stega` on npm](https://www.npmjs.com/package/@vercel/stega)
