# Dropl docs

# Getting started

Source: https://www.dropl.io/docs/getting-started

> Set up your account and first client site, embed a video and a showcase, and invite your team and clients.

Dropl hosts your clients' videos and photos and gives you a snippet to paste into their website. After launch, clients can update that media themselves, without you editing the site.

By the end of this guide you'll have:

- An **account** with your first **client site**
- A **video** playing on a web page
- A **showcase** of photos and videos on a web page
- Your **team** and a **client** invited

## How Dropl is organized

Three words come up everywhere. Learn them once.

| Term | What it is |
| --- | --- |
| **Account** | Your business or studio. Billing, your team, and every client site live here. |
| **Client site** | One website you look after. Each site has its own videos, showcases, folders, and player settings. |
| **Media** | The page where you manage one client site's videos and showcases. |
| **Collection** | A list of items your client edits, like a menu or an inventory. See [Collections](https://www.dropl.io/docs/collections). |

You switch between client sites from the dashboard.

## 1. Create your account

1. Go to [Sign up](https://www.dropl.io/signup) and create your login.
2. Enter your **Business or brand name**. This is your account name. Teammates see it when you invite them.
3. Enter **Your first website**. Use your own site or your first client's, like `acmebakery.com`.
4. Choose what to add first: **Showcases** or **Videos**. You can do both later.

Your free trial starts right away and lasts **14 days**. No card needed yet.

### Add more client sites

Owners and admins can add a site any time:

1. Open **Settings → Sites**.
2. Under **Add a client site**, type the site name and, optionally, the client's website.
3. Click **Add site**.

How many sites you can add depends on your plan. See [Pricing](https://www.dropl.io/pricing).

Saving a website doesn't limit anything: embeds work on any website until you turn on embed protection in the site's settings. See [Client sites and domains](https://www.dropl.io/docs/client-sites/domains-and-embed-protection).

## 2. Upload a video and embed it

1. Open **Media** for your client site.
2. Click **Upload**, or drag files anywhere onto the page.
3. Wait for processing. The video plays as soon as it's ready.

Common formats like MP4, MOV, and WebM work. Each file can be up to **20 GB**.

### Copy the embed code

Click the **code icon** on the video, or open its **⋮ menu → Copy embed code**. You get a snippet like this:

```html
<div data-dropl-video="Xk3pQ9vLm2"></div>
<script src="https://www.dropl.io/embed/player.js" async></script>
```

Paste it into the page where the video should play.

### Choose who can watch

Open the video and set **Visibility** under **Details**:

- **Public**: anyone can watch, and search engines may list it.
- **Unlisted**: anyone with the link can watch. Never listed or indexed.
- **Private**: only people with access to this client site can watch.

You can also add a **password**, or turn off the video's **watch page** so it only plays in embeds.

> **Tip:** Need to swap a video later? Replace it from the video's page. The link and every embed stay the same.

## 3. Create a showcase and embed it

A showcase is a gallery of photos, videos, or both. Changes you make in Dropl show up on the website automatically.

1. In **Media**, click **New showcase**.
2. Give it a title, like "Project gallery", and click **Create showcase**.
3. Add media:
   - **Photos:** click **Choose photos** or drag them in. JPEG, PNG, WebP, AVIF or HEIC, up to **20 MB** each and **100 at a time**.
   - **Videos:** click **Add videos** to pick from this site's library.

### Make it look right

All of these are in the showcase's settings:

- **Layout:** Grid or Collage.
- **Grid tiles:** **Crop to fill** for even tiles, or **Fit whole item** to show each photo uncropped.
- **Show category filters:** create categories, select items, and use **Add to category**. Visitors get filter tabs above the showcase.
- **"Load more" button:** show a few items first, then load the rest on click.

### Copy the embed code

Find **Embed on a website** and click **Copy embed code**:

```html
<div data-dropl-showcase="k3p9vlm2"></div>
<script src="https://www.dropl.io/embed/showcase.js" async></script>
```

Only want one category on a page? Pick it under **Show** before copying. The embed shows just that category, without filter tabs:

```html
<div data-dropl-showcase="k3p9vlm2" data-category="kitchens"></div>
<script src="https://www.dropl.io/embed/showcase.js" async></script>
```

> **Note:** Private and password-protected videos never appear in a showcase. Make them public or unlisted first.

### Where you can paste embeds

Every embed is plain HTML plus a script that runs in the visitor's browser. That means it works almost anywhere:

- **Site builders** like WordPress, Webflow, and Framer: use their custom HTML or embed block.
- **Static sites**, including Next.js static exports and sites on Cloudflare Pages: paste it into your page markup.
- **Hand-coded sites:** paste it into the HTML.

No server code, API keys, or rebuilds needed. Older snippets that use `data-dropl-gallery` keep working.

## 4. Invite your team and clients

Dropl has two kinds of people: your **team** and your **clients**.

| | Team members | Clients |
| --- | --- | --- |
| **Sees** | Every client site | Only the sites they're invited to |
| **Uses a seat** | Yes | No |
| **Invite from** | Settings → Members | The client site |

### Invite a teammate

1. Open **Settings → Members**.
2. Under **Invite a teammate**, enter their email and pick a role.
3. Click **Send invite**. They get an email with a link to join.

Roles:

- **Owner:** everything, including billing and the team. Only owners can add other owners.
- **Admin:** everything, including billing, the team, and client sites.
- **Team member:** works on every client site. No billing, team, or site settings.

### Invite a client

1. Open the client site's **Media** page and click **Clients**. (Or use **Settings → Sites → Clients**.)
2. Under **Invite a client**, enter their email and send.

Clients only see their own site. They can build showcases, upload videos, and copy embed codes, so they can keep their website fresh without you.

## Next steps

You're set up. Here's where to go from here:

- **Make the player yours:** open **Settings → Player** to set colors and controls for each client site.
- **Keep embeds on your client's website:** save their domains and turn on embed protection. See [Client sites and domains](https://www.dropl.io/docs/client-sites/domains-and-embed-protection).
- **Keep an eye on usage:** **Usage** shows storage and bandwidth for your account.
- **Pick a plan:** compare Dropl on [Pricing](https://www.dropl.io/pricing), then choose one under **Billing**.
- **Let your AI assistant do the setup:** connect Cursor or Claude Code and have it upload media and paste embeds. See [Set up with AI](https://www.dropl.io/docs/ai-and-api/set-up-with-ai).
- **Questions?** [Contact us](https://www.dropl.io/contact).

More guides are on the way. Browse everything in the [docs home](https://www.dropl.io/docs).

---

# Projects layout

Source: https://www.dropl.io/docs/showcases/projects

> Turn a showcase into a portfolio, with a page for each project and its own photos, description, and details.

A **Projects** showcase is a portfolio. Instead of one set of photos, it holds projects: each one has a title, a subtitle, a description, a cover, its own photos and videos, and details like square footage or the year it was finished. On the website, visitors see a card for each project and open its page right inside the embed.

Your clients can add and edit projects too, from the dashboard or their phone.

## Create a Projects showcase

1. In **Media**, click **New showcase**.
2. Under **Type**, choose **Projects**.
3. Give it a title, like "Our work", and click **Create showcase**.

You can switch a showcase between **Gallery** and **Projects** in **Display** while it's empty. Once it has photos, videos, or projects, the type stays as it is.

## Add projects

1. In the showcase, click **Add project**.
2. Type a title and, if you want, a subtitle (like "Custom Home · Zebulon, NC") and a description.
3. On the project's page, add photos and videos the same way as in a gallery: drag them in, or use **Choose photos** and **Add videos**.

Each project's page also has:

- **Change cover:** pick which photo shows on the project's card. Without a choice, the first photo is the cover.
- **Categories:** tag projects so visitors can filter them, like "Kitchens" or "Decks". Create categories from **Manage categories** on the showcase.
- **Advanced:** the project's web address name (its slug), used in links like `/work/lakeside-kitchen`.

Drag projects in the list to change their order, or use the **⋯** menu next to each one. To move photos between projects, select them and click **Move to project**.

A project only shows on the website once it has at least one photo or video ready. Until then, the list says **Not on your website yet**.

> **Note:** Deleting a project deletes its photos too. Its videos stay in the site's library.

## Project details

Project details are the facts every project in the showcase fills in, like "Square feet" or "Year finished". Owners, Admins, and Members define them once per showcase; clients fill in the values on each project.

Open the showcase's **⋯** menu and choose **Project details**. Each showcase can have up to 8 details. The types are Short text, Number, Single select, Year, Date, and Link:

- **Number** details can have a unit, like "sq ft", shown after the value.
- **Select** details pick from a list of options you define, like the project type.
- Turn on **Show on project cards** to show a detail under the title on each card, for up to 2 details.

Click **Review and save** to see the changes before they're saved. Removing a detail, or an option that projects use, clears those values; the review says how many projects are affected before anything is saved.

## Embed it

Click **Get embed code** in the showcase. The default snippet shows a card for every project. Clicking a card opens the project in the embed, and the browser's back button returns to the list:

```html
<div data-dropl-showcase="k3p9vlm2"></div>
<script src="https://www.dropl.io/embed/showcase.js" async></script>
```

Under **Show**, you can also pick:

- **Only … projects:** just the projects in one category, without filter tabs.
- **One project's page:** a single project, for a page about that project. The snippet adds a `data-project` attribute with the project's slug:

```html
<div data-dropl-showcase="k3p9vlm2" data-project="lakeside-kitchen"></div>
<script src="https://www.dropl.io/embed/showcase.js" async></script>
```

### Link cards to your own project pages

If the website already has a page for each project, type its address in **Link cards to your own project pages**, with `{slug}` where the project's slug goes. Cards then link to those pages instead of opening the project in place. The snippet adds a `data-project-url` attribute:

```html
<div data-dropl-showcase="k3p9vlm2" data-project-url="/work/{slug}"></div>
<script src="https://www.dropl.io/embed/showcase.js" async></script>
```

The address can be a path on the same website, like `/work/{slug}`, or a full `https://` link. On each of those pages, embed that project with `data-project`.

> **Tip:** Changing a project's slug changes its address. Update any links or `data-project` snippets that use the old one.

## Related

- [Getting started](https://www.dropl.io/docs/getting-started): create your first showcase and embed it.
- [Client sites and domains](https://www.dropl.io/docs/client-sites/domains-and-embed-protection): limit where showcases load.
- [Set up with AI](https://www.dropl.io/docs/ai-and-api/set-up-with-ai)

---

# Collections

Source: https://www.dropl.io/docs/collections

> Structured content your clients edit themselves, like menus, inventory, events, and listings, that your website reads from Dropl.

A **collection** is a list of items with the same fields, like a restaurant menu, an equipment inventory, or a class schedule. You design the fields once. Your client then adds and edits items from the Dropl dashboard on their phone, and your website reads the published items from Dropl.

The fastest way to set one up is to describe the content to your AI assistant. See [Set up Collections with AI](https://www.dropl.io/docs/collections/set-up-with-ai).

## Create a collection

1. Open **Collections** in the sidebar and pick the client site.
2. Click **New collection** and start from a template (Menu, Inventory, and Events) or from scratch.
3. On the **Fields** tab, add, rename, or reorder fields. A collection can have up to 50 fields.

Each collection belongs to one client site, like its showcases.

## Field types

| Type | Key in the API | What your website receives |
| --- | --- | --- |
| Short text | `short_text` | string |
| Long text | `long_text` | `{ markdown, html }` (safe HTML: bold, italic, links, bulleted lists) |
| Number | `number` | number |
| Price | `price` | `{ amount, currency, formatted }`, e.g. `formatted: "$14.50"` |
| Date | `date` | `YYYY-MM-DD` string |
| Date and time | `datetime` | ISO 8601 string in UTC |
| Toggle | `toggle` | boolean (never null) |
| Single select | `select` | the option's value |
| Multi-select / tags | `multi_select` | array of option values |
| Image | `image` | `{ id, altText, width, height, placeholderColor, srcset }` |
| Images | `images` | array of images |
| Link | `link` | URL string |

Every field has a **label** (what your client sees), optional **help text** shown under it while editing, and a **key**. The key is set when the field is first saved and never changes, even if you rename the label later, so your website's code keeps working.

## Changing fields safely

Adding a field is always safe. Renaming a field, changing its type, removing it, or removing a select option can lose data or break the website, so Dropl shows exactly what will change and how many items are affected, and asks you to confirm.

If someone else changed the fields after you opened them, Dropl won't overwrite their change. Reload the fields and try again.

The **Activity** tab shows who changed what, including changes made through the API or an AI assistant, which show the name of the API key they used (for example `API key "Cursor"`). The most recent schema change can be undone there while no data would be lost.

## Items

On the **Items** tab you can search, filter, reorder by dragging, duplicate, and publish or unpublish items in bulk.

- **Published** items appear on the website. **Drafts** never do.
- New items are published unless you save them as a draft.
- Deleted items go to the trash and can be restored for 30 days. Deleting a whole collection works the same way.

### Import and export

On the **Import & export** tab, upload a CSV file. Dropl matches columns to fields, shows a preview, and imports the valid rows. Rows with problems are listed with the row number and the field, so you can fix them and import just those again.

You can export any collection as CSV or JSON, or every collection of a site at once, so your client's content is never locked in.

## What your clients see

Invite a client to their site from **Settings → Sites**. Their sidebar lists each collection by name under **Your site**. Clients can add, edit, reorder, publish, import, and delete items. They can't change fields, settings, or the website integration. Clients with view-only access can look but not edit.

The item form is built for phones: price fields open a number keypad, dates use the phone's date picker, and photos can be taken with the camera.

## Plan limits

Each plan includes a number of collection items across your account. Items in the trash don't count. The **Usage** page shows how many you've used, and Dropl warns you at 80% and 100%. When you reach the limit, existing items keep showing on websites; only adding new ones is paused. You can add more items with an add-on from **Billing**. See [pricing](https://www.dropl.io/pricing) for each plan's limits.

## Next steps

- [Set up Collections with AI](https://www.dropl.io/docs/collections/set-up-with-ai): describe the content, and let your assistant build it.
- [Show collections on your website](https://www.dropl.io/docs/collections/website-api): the public endpoint, filters, and a Next.js example.

---

# Set up Collections with AI

Source: https://www.dropl.io/docs/collections/set-up-with-ai

> Describe your client's content in plain language and let Cursor, Claude Code, or another MCP client design the collections, import the content, and wire up the site.

The quickest way to set up [collections](https://www.dropl.io/docs/collections) is to describe the content to your AI coding assistant. With the Dropl MCP server connected, it designs the fields, shows you the plan, creates the collections after you approve, imports the content your site already has, and replaces the hard-coded content with live data from Dropl.

You stay in control: nothing is created until you approve the plan, and changes that could lose data need your explicit go-ahead.

## 1. Connect Dropl to your assistant

Follow [Set up with AI](https://www.dropl.io/docs/ai-and-api/set-up-with-ai) to add the MCP server and sign in. Leave the three **Collections** permissions ticked when you approve the sign-in:

| Permission | What it allows |
| --- | --- |
| `collections:read` | Read collections, their fields, and items (drafts included) |
| `collections:write` | Add, edit, reorder, and delete items |
| `collections:schema` | Create collections and change their fields |

A key without `collections:schema` can manage content but can never change a collection's structure.

## 2. Write a brief

Describe what your client needs to edit, the way you'd explain it to a developer:

- **What the items are:** dishes, machines, courses, projects, jobs.
- **What each item has:** name, description, price, photos, dates, links.
- **Fixed choices:** categories or tags, with their options (for example starters, mains, desserts).
- **Yes/no switches:** sold out, featured, available.
- **What's required**, and anything your client might get wrong, so the assistant can add help text.

You can also leave the brief short and point the assistant at the page where the content is hard-coded. It reads the code and suggests the fields.

In the dashboard, open **Collections** and click **Set up with AI**, then pick **Make content editable (Collections)** to fill in a brief and copy a complete prompt.

## 3. What the assistant does

1. **Reads first.** It lists the site's collections and reads the current fields of any that already exist, including edits you or your client made in the dashboard.
2. **Plans.** It designs the collections (fields, types, options, required fields, the title field, and friendly help text) and runs `plan_collections`. This is a dry run: nothing is saved.
3. **Asks you.** It shows you the plan as a plain-text summary, like `Add field "Spice level"` or `Remove field "Notes": 12 items lose their value.`
4. **Applies.** After you approve, it creates or updates the collections with `apply_collection_plan`. Up to 10 collections can be planned and applied at once.
5. **Imports.** It finds the content already in your project (arrays, JSON files, repeated markup) and imports it with `add_collection_items`. It dry runs first and shows you any items that don't fit the fields.
6. **Wires up the site.** It calls `get_collection_code` for TypeScript types and a fetch example, and replaces the hard-coded content with live data, following your project's conventions.
7. **Checks its work.** It runs your build and fixes what it broke.
8. **Hands off.** Invite your client from **Settings → Sites** so they can edit the content from their phone.

## Changes need your approval

Adding fields is always safe. Renaming or removing a field or option, or changing a field's type, can lose data or confuse the people editing it, so it's **destructive**. Dropl refuses destructive changes unless the assistant passes `confirmDestructive`, and the assistant is told to do that only after you explicitly agree.

If you or your client changed the collection in the dashboard after the assistant read it, Dropl refuses the plan as a conflict instead of overwriting your edits. The assistant reads the fields again and builds a new plan. Your manual edits always win.

Applying the same plan twice doesn't create duplicates, and retrying an import doesn't add the same items twice.

Made a change you didn't want? The assistant can undo the most recent schema change with `undo_collection_change`, or you can click **Undo** on the collection's **Activity** tab, as long as no data would be lost.

## Example briefs

Copy a prompt below and paste it into your assistant's chat, then adjust the details for your client.

### Restaurant menu

```text
Use the Dropl MCP tools to make this site's content editable with Dropl Collections.

This is a restaurant site. The client needs to edit the menu: dishes with a name, description, price, a photo, and a category (starters, mains, desserts, drinks), plus dietary tags (vegan, gluten-free, spicy) and a sold-out toggle. They also post weekly specials with a start and end date.

Read the client site's existing collections first. Show me the plan from plan_collections and wait for my confirmation before applying it. Then import the content that's hard-coded in the project (dry run first), replace it with live data using get_collection_code, and run the build.
```

### Equipment inventory

```text
Use the Dropl MCP tools to make this site's content editable with Dropl Collections.

This is an equipment rental and sales site. The client needs to manage their inventory: each machine has a name, make, model, year, hours of use, condition (new, used, refurbished), price, a short description, several photos, and an available toggle. Visitors filter by category (excavators, loaders, trailers, attachments).

Read the client site's existing collections first. Show me the plan from plan_collections and wait for my confirmation before applying it. Then import the content that's hard-coded in the project (dry run first), replace it with live data using get_collection_code, and run the build.
```

### Training course schedule

```text
Use the Dropl MCP tools to make this site's content editable with Dropl Collections.

This is a training provider's site. The client needs to publish upcoming courses: course name, description, start date and time, end date and time, location (or online), instructor, price, seats available, a booking link, and a level (beginner, intermediate, advanced). Past courses should be easy to hide.

Read the client site's existing collections first. Show me the plan from plan_collections and wait for my confirmation before applying it. Then import the content that's hard-coded in the project (dry run first), replace it with live data using get_collection_code, and run the build.
```

### Contractor project portfolio

```text
Use the Dropl MCP tools to make this site's content editable with Dropl Collections.

This is a home renovation contractor's site. The client needs to add finished projects: project name, town, a description, completion date, project type (kitchen, bathroom, deck, addition), a cover photo and a few more photos, the budget range, and a featured toggle for the home page.

Read the client site's existing collections first. Show me the plan from plan_collections and wait for my confirmation before applying it. Then import the content that's hard-coded in the project (dry run first), replace it with live data using get_collection_code, and run the build.
```

### Job listings

```text
Use the Dropl MCP tools to make this site's content editable with Dropl Collections.

This is a company careers page. The client's HR team needs to post open roles: job title, department, location, employment type (full-time, part-time, contract), salary range, a description with responsibilities and requirements, an apply link, a closing date, and a remote-friendly toggle.

Read the client site's existing collections first. Show me the plan from plan_collections and wait for my confirmation before applying it. Then import the content that's hard-coded in the project (dry run first), replace it with live data using get_collection_code, and run the build.
```

## The Collections tools

| Tool | What it's for |
| --- | --- |
| `list_collections` | A site's collections, item counts, and plan limits |
| `get_collection_schema` | A collection's current fields and version |
| `plan_collections` | Preview creating or changing collections, without saving |
| `apply_collection_plan` | Apply an approved plan |
| `add_collection_items` | Import items, with errors for each item that doesn't fit |
| `list_collection_items` | Search and filter items |
| `get_collection_code` | TypeScript types and a Next.js example for the website |
| `undo_collection_change` | Undo the most recent schema change |

## Troubleshooting

**"Someone changed this collection since you read it."** Fields were edited after the assistant read them. Ask it to read the collection again and make a new plan.

**The assistant is missing a permission (`INSUFFICIENT_SCOPE`).** The connection was approved without a Collections permission. Run `npx -y @dropl/mcp login` again and leave the Collections permissions ticked.

**Some items weren't imported.** The import reports each item's problem by field. Ask the assistant to fix those items and import only them again.

**The plan's item limit is reached.** Existing items keep showing on the website. Remove items you don't need, or add more from **Billing**.

## Next steps

- [Show collections on your website](https://www.dropl.io/docs/collections/website-api): what the assistant's code calls, if you want to write it yourself.
- [Collections](https://www.dropl.io/docs/collections): fields, items, imports, and what clients see.

---

# Show collections on your website

Source: https://www.dropl.io/docs/collections/website-api

> Read a collection's published items from Dropl's public endpoint, with filters, sorting, paging, TypeScript types, and a Next.js example.

Each public collection has a **public items URL**. Your website reads published items from it without an API key. Find it on the collection's **Integrate** tab, or ask your AI assistant to call `get_collection_code`.

```text
https://www.dropl.io/api/public/collections/m7qk2xr9/items
```

Only **published** items are returned. Drafts and items in the trash never appear, whether you read from a browser or a server.

## Request options

| Query parameter | Example | What it does |
| --- | --- | --- |
| `limit` | `limit=20` | Items per page, up to 100 (default 50) |
| `offset` | `offset=20` | Skip this many items; use `nextOffset` from the previous page |
| `sort` | `sort=-price` | `position` (the order set in Dropl, default), `createdAt`, `updatedAt`, `publishedAt`, `title`, or a field key. Prefix `-` for descending |
| `filter[key]` | `filter[category]=mains,desserts` | Items whose field equals any of the comma-separated values |
| `filter[key][ne]` | `filter[sold_out][ne]=true` | Items whose field doesn't equal the value |
| `filter[key][gte]`, `filter[key][lte]` | `filter[price][lte]=20` | Ranges for numbers, prices, and dates |
| `filter[key][contains]` | `filter[tags][contains]=vegan` | Text that contains the value, or lists that include it |
| `q` | `q=pasta` | Search titles and text fields |
| `fields` | `fields=name,price` | Return only these field keys |

Read one item by its slug or id at `…/items/{slug}`.

## Response

```json
{
  "collection": { "publicId": "…", "name": "Menu", "slug": "menu", "timezone": "America/Chicago", "fields": [{ "key": "name", "label": "Dish", "type": "short_text", "options": null }] },
  "items": [
    { "id": "…", "slug": "margherita", "position": 0, "publishedAt": "…", "updatedAt": "…", "fields": { "name": "Margherita", "price": { "amount": 14.5, "currency": "USD", "formatted": "$14.50" } } }
  ],
  "total": 24,
  "limit": 20,
  "offset": 0,
  "nextOffset": 20,
  "expiresAt": "…"
}
```

Items are keyed by **field key**, not label, so renaming a field in the dashboard doesn't break your site. Empty optional fields are `null`; toggles are always `true` or `false`.

| Type | Key in the API | Value |
| --- | --- | --- |
| Short text | `short_text` | string |
| Long text | `long_text` | `{ markdown, html }` (safe HTML: bold, italic, links, bulleted lists) |
| Number | `number` | number |
| Price | `price` | `{ amount, currency, formatted }`, e.g. `formatted: "$14.50"` |
| Date | `date` | `YYYY-MM-DD` string |
| Date and time | `datetime` | ISO 8601 string in UTC |
| Toggle | `toggle` | boolean (never null) |
| Single select | `select` | the option's value |
| Multi-select / tags | `multi_select` | array of option values |
| Image | `image` | `{ id, altText, width, height, placeholderColor, srcset }` |
| Images | `images` | array of images |
| Link | `link` | URL string |

Image URLs are signed and stay valid until `expiresAt`, so don't store them; fetch the items again instead. Each image has a `srcset` of WebP sizes, narrowest first.

## TypeScript types and a Next.js example

The collection's **Integrate** tab (and `get_collection_code` for AI assistants) generates TypeScript types from the current fields and a Next.js example that fetches the items. Generate them again after changing fields.

A minimal server component looks like this:

```tsx
const MENU_URL = "https://www.dropl.io/api/public/collections/m7qk2xr9/items";

export default async function MenuPage() {
  const response = await fetch(`${MENU_URL}?limit=100`, { next: { revalidate: 60 } });
  if (!response.ok) throw new Error(`Dropl returned ${response.status}`);
  const { items } = await response.json();
  return (
    <ul>
      {items.map((item: { id: string; fields: { name: string } }) => (
        <li key={item.id}>{item.fields.name}</li>
      ))}
    </ul>
  );
}
```

## Caching

Responses are cached for 60 seconds, so edits show up on the website within about a minute. Revalidating your pages on the same interval (as in the example) keeps them current without extra requests.

## Private collections and embed protection

Collections follow the client site's [embed protection](https://www.dropl.io/docs/client-sites/domains-and-embed-protection): if the site only allows its own domains, the public endpoint only answers requests from those domains and from servers.

A **private** collection has no public URL. Read it from your server through the [Public API](https://www.dropl.io/docs/ai-and-api/public-api) with an API key that has `collections:read`, and keep the key out of the browser.

## Writing content from your own code

The [Public API](https://www.dropl.io/docs/ai-and-api/public-api) has endpoints to create collections, change fields (with a dry run and the same destructive-change confirmation as the dashboard), and add up to 500 items per request with errors reported for each item. See the OpenAPI document for every endpoint.

---

# Feedback

Source: https://www.dropl.io/docs/feedback

> Your clients point at anything on their live website and request a change. Each request reaches you with the page, element, screenshot, and device.

**Feedback** covers the website changes your client can't make themselves in Dropl: a headline rewrite, a new section, a broken link, a bigger button. Instead of an email full of screenshots, your client opens their site from the client portal, taps the thing they want changed, and describes it.

The rule for clients is simple: if it's in Dropl, change it yourself. If it isn't, point at it and ask.

Feedback is available on the Dropl plans.

## How it works

1. You add the Dropl script to the client's website once. See [Install the Dropl script](https://www.dropl.io/docs/feedback/install).
2. Your client clicks **Request a website change** in the client portal. Their site opens with the feedback toolbar.
3. They tap an element and leave a comment, change some text, or send a general request.
4. The request shows up in **Feedback** in your dashboard, with everything you need to find the spot again.
5. You reply, change the status, and mark it done with a note. Your client gets an email.

Regular visitors never see the toolbar. The script does nothing unless someone opened the site from the portal.

## Request types

| Type | What the client does |
| --- | --- |
| **Comment** | Points at something and describes the change. On a photo that isn't part of a Dropl showcase, they can ask to **Replace** it (with a new photo) or **Remove** it. |
| **Text change** | Taps a heading, paragraph, button, or link, and types the new wording. You get it as "from → to". |
| **General** | A request not tied to one spot, like "Add a page for our new location". |

Clients can attach photos to comments and general requests.

## What each request includes

- The page URL and title.
- The element: a CSS selector, the start of its text, and its position on the page.
- For text changes, the current text and the requested text.
- A screenshot of the client's view with the element highlighted. Form fields and passwords are masked.
- Device type, browser, screen and window size, and scroll position.
- Who asked, and when.

## Statuses

| Status | Meaning |
| --- | --- |
| **Open** | New, not started. |
| **In progress** | You're working on it. |
| **Done** | Finished. Add a note saying what you changed; your client gets an email. |
| **Won't do** | Not going ahead. Add a note saying why. |

Your team can set any status. Clients can reopen a **Done** request if it isn't quite right. Every change shows in the request's thread.

## Next steps

- [Install the Dropl script](https://www.dropl.io/docs/feedback/install): add it to any website, with steps for each platform.
- [Resolve feedback with AI](https://www.dropl.io/docs/feedback/ai-resolves-feedback): let Cursor or Claude Code work through the open requests.
- [Client sites and domains](https://www.dropl.io/docs/client-sites/domains-and-embed-protection): the toolbar only works on a site's saved domains.

---

# Install the Dropl script

Source: https://www.dropl.io/docs/feedback/install

> Add one script tag to your client's website so they can request changes from the page. Steps for Next.js, WordPress, Webflow, Framer, Squarespace, Wix, Shopify, and HTML.

The Dropl script turns on the [feedback toolbar](https://www.dropl.io/docs/feedback) for your client. You add it to the site's `<head>` once, and it works on every page.

Available on the Dropl plans.

## What the script does

- **Nothing for regular visitors.** It loads asynchronously, shows no interface, and makes no network requests unless the visitor opened the site with a feedback link.
- **Shows the toolbar for your client.** The **Request a website change** button in the client portal opens the site with a private feedback link. The browser remembers it, so your client doesn't have to press the button every time.
- **Never changes the site.** The toolbar runs in its own Shadow DOM, so your CSS can't break it and it can't break your CSS. It only reads the page to describe the request.

## Get your script tag

In the dashboard, open **Feedback** and the client site's **Feedback settings**, and copy the script tag. It looks like this, with your client site's ID in `data-site`:

```html
<script src="https://www.dropl.io/embed/d.js" data-site="q4n8w2zt" async></script>
```

The site ID is 8 to 16 lowercase letters and numbers. Use the tag from your dashboard rather than this example.

## Add it to the website

Paste the tag into the `<head>` of every page. Most platforms have one place for that.

### Next.js and AI-built sites

Add the script to the root layout, `app/layout.tsx`, with `next/script`:

```tsx
import Script from "next/script";

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en">
      <body>
        {children}
        <Script src="https://www.dropl.io/embed/d.js" data-site="q4n8w2zt" strategy="afterInteractive" />
      </body>
    </html>
  );
}
```

A plain `<script async>` tag inside `<head>` in the same file works too. For a site built with Lovable, Bolt, v0, or a similar tool, ask it to "add this script tag to the head of every page" and paste the tag.

### WordPress

Paste the tag into your site's header:

1. With a header and footer code plugin, add the tag to the **Header** section of every page and save.
2. Or, in a child theme, paste it into `header.php` just before `</head>`.
3. Clear any page cache, then open the site once with **Request a website change** so the dashboard detects it.

**Dropl plugin: Coming soon.** A Dropl plugin for the WordPress.org plugin directory is on its way. Once it's approved, you'll install it from **Plugins → Add New**, paste the site ID under **Settings → Dropl**, and turn it on. Until then, use the script tag above.

### Webflow

1. Open **Site settings → Custom code**.
2. Paste the tag into **Head code** and click **Save changes**.
3. Publish the site.

Custom code needs a paid Webflow site plan.

### Framer

1. Open **Site settings → General** and scroll to **Custom code**.
2. Paste the tag into the field for the end of the `<head>` tag.
3. Publish the site.

Custom code needs a paid Framer plan.

### Squarespace

1. Open **Settings → Advanced → Code injection**.
2. Paste the tag into **Header** and click **Save**.

Code injection needs a Business plan or higher.

### Wix

1. Open **Settings → Custom code** (under **Advanced**) and click **Add custom code**.
2. Paste the tag, choose **All pages** (load once), and place it in **Head**.
3. Click **Apply**.

Custom code needs a Wix premium plan with a connected domain.

### Shopify

1. Open **Online Store → Themes**, click **⋯** next to your theme, and choose **Edit code**.
2. Open `layout/theme.liquid` and paste the tag just before `</head>`.
3. Click **Save**.

### Plain HTML

Paste the tag inside `<head>` on every page, or in the shared header template if your site has one.

## Save the site's domains

The toolbar only starts on the client site's saved **Website domains**, so a feedback link can't be used on another website. Add every domain the site uses, like `example.com` and any staging domain. See [Website domains](https://www.dropl.io/docs/client-sites/domains-and-embed-protection#website-domains).

To try the toolbar on your computer, turn on **Allow localhost for testing** in the site's settings. For Feedback, the domain check applies whether or not embed protection is on. See [Testing on your computer](https://www.dropl.io/docs/client-sites/domains-and-embed-protection#testing-on-your-computer).

## Test it

1. Open the client portal as your client would, or use **Request a website change** yourself.
2. Your site opens with the toolbar at the bottom of the screen.
3. Back in the dashboard, the site's **Feedback settings** show **Detected on** your domain, with the time it was last seen.

Dropl notices the script the first time someone opens the site this way, so the status only changes after that first visit.

## Content Security Policy

If the site sends a `Content-Security-Policy` header, allow Dropl's domains:

| Directive | Allow | Why |
| --- | --- | --- |
| `script-src` | `https://www.dropl.io` | The script and the toolbar it loads |
| `connect-src` | `https://www.dropl.io` | Sending requests and replies |
| `img-src` | `https://cdn.dropl.io` `https://video.dropl.io` `blob:` `data:` | Screenshots and photos in the toolbar, and taking the screenshot |

For example:

```text
Content-Security-Policy: default-src 'self'; script-src 'self' https://www.dropl.io; connect-src 'self' https://www.dropl.io; img-src 'self' https://cdn.dropl.io https://video.dropl.io blob: data:
```

Add these sources to your existing policy rather than replacing it. If the page loads images from other domains that the policy doesn't let it fetch, the screenshot shows placeholders for them; the request is still sent.

## Privacy

- **Regular visitors:** nothing is captured or sent. The browser downloads the script, like any other script.
- **Your client and team, with a feedback link:** when they send a request, Dropl receives the page URL and title, the element they picked, a screenshot of their own view, device and browser details, and their message and photos.
- **Masking:** form fields and password fields are masked in screenshots.
- **No recording:** only the moment they send a request is captured. There's no session recording or analytics.
- **Turning it off:** the toolbar has **Turn off on this browser**, which forgets the feedback link. Links expire after 30 days, and you can revoke every link for a site from its **Feedback settings**.

Screenshots and photos count toward your account's storage.

## Troubleshooting

**The dashboard says the script isn't detected.** Open the site once with **Request a website change**; detection happens then. If it still isn't detected, view the page source and check the tag is in `<head>` with the right `data-site`, that the site is published, and that a cache plugin or CDN isn't serving an old copy.

**The toolbar doesn't appear.** Check that the domain in the address bar is one of the site's saved domains, that Feedback is turned on for the site, and that the browser's console doesn't show a Content Security Policy error. If it does, see [Content Security Policy](https://www.dropl.io/docs/feedback/install#content-security-policy).

**The feedback link expired, or the toolbar stopped showing.** Links last 30 days and stop working when they're revoked. Press **Request a website change** in the client portal again for a fresh one.

**Feedback isn't available.** Feedback isn't included on the legacy Solo plan. Upgrade from **Billing** to turn it on. Requests sent before a downgrade stay in your dashboard.

## Next steps

- [Feedback](https://www.dropl.io/docs/feedback): request types, statuses, and what each request includes.
- [Resolve feedback with AI](https://www.dropl.io/docs/feedback/ai-resolves-feedback): let your AI assistant work through the requests.
- [Client sites and domains](https://www.dropl.io/docs/client-sites/domains-and-embed-protection): saved domains and localhost testing.

---

# Resolve feedback with AI

Source: https://www.dropl.io/docs/feedback/ai-resolves-feedback

> Let Cursor, Claude Code, or another MCP client read your clients' feedback, make the changes in your project, and mark each request done with a note.

Every [feedback request](https://www.dropl.io/docs/feedback) carries the page, the element, the current and requested text, a screenshot, and the device. That's enough context for your AI coding assistant to find the spot in your code and make the change. You type "fix the open Dropl feedback for this site", review what it did, and your client gets an email for each finished request.

## 1. Connect Dropl to your assistant

Follow [Set up with AI](https://www.dropl.io/docs/ai-and-api/set-up-with-ai) to add the MCP server and sign in. Leave the two **Feedback** permissions ticked when you approve the sign-in:

| Permission | What it allows |
| --- | --- |
| `feedback:read` | List requests and read them with their context and thread |
| `feedback:write` | Reply to requests and change their status |

Connected before Feedback existed? Your key doesn't have these permissions yet. Run `npx -y @dropl/mcp login` again and approve, or create a new key with the Feedback permissions.

## 2. Ask for the fixes

Open the client's website project in your editor and paste one of the prompts below.

## What the assistant does

1. **Lists the requests.** `list_feedback` returns the site's open and in-progress requests. It can filter by status, type, and page.
2. **Reads each one.** `get_feedback` returns the page URL, the element (selector, text hint, and position), the current and requested text, a screenshot link, the device and window size, and the thread.
3. **Finds the code.** It searches your project for the text or the element on that page.
4. **Makes the change.** Text changes can usually be applied directly. For anything unclear, it replies to the client with `reply_to_feedback` instead of guessing.
5. **Checks its work.** It runs your build.
6. **Marks it done.** `update_feedback_status` sets the request to **Done** with a short note saying what changed. Your client gets an email with the note.

Nothing on the live site changes until you deploy, so you review the code first.

## Guidance for the assistant

The Dropl tools tell the assistant to apply text changes directly and to ask when a request is ambiguous. These rules are worth repeating in your prompt:

- **Apply text changes directly** when the current text is found and the new text is clear.
- **Ask, don't guess.** If a request is ambiguous, can't be found, or needs a decision (design, content, cost), reply asking the client to clarify and leave it open.
- **Mark each request done with a short note** saying what changed, in plain language for the client. Use **Won't do** with a reason when a request isn't going ahead.
- **Don't close what isn't finished.** Use **In progress** for work that's started but not deployed.

## Prompts to copy

### Fix the open feedback

```text
Fix the open Dropl feedback for this site. Use list_feedback to find the open requests and get_feedback to read each one, including the screenshot and the element details. Make the changes in this project. Apply text changes directly. If a request is ambiguous or you can't find the element, reply to the client with reply_to_feedback asking what they mean instead of guessing, and leave it open. Run the build, then mark each finished request done with update_feedback_status and a short note for the client saying what you changed.
```

### Apply text changes only

```text
Apply all open text-change requests in Dropl for the client site "SITE NAME". Use list_feedback with type text_change, then get_feedback for each request to see the current and requested text and the page. Find the current text in this project and replace it with the requested text exactly. If the current text appears in more than one place, or you can't find it, reply to the client asking which one they mean and skip it. Run the build, then mark each changed request done with a short note like: Changed the homepage heading to "...".
```

### Ask about anything unclear

```text
Go through the open Dropl feedback for this site. Don't change any code yet. For each request that's ambiguous, missing details, or needs a decision from the client, reply with reply_to_feedback asking one clear question in plain language. Then give me a list of the requests you asked about and the ones that are clear enough to do.
```

### Summarize by page

```text
Summarize the open Dropl feedback for this site, grouped by page. For each request, give the number, the type, who asked, what they want in one line, and how much work it looks like (quick text change, small layout change, or bigger). Don't change any code or statuses.
```

## The Feedback tools

| Tool | What it's for |
| --- | --- |
| `list_feedback` | A site's requests. Defaults to open and in progress; filter by `status`, `type`, and `page` |
| `get_feedback` | One request with its page, element, text, screenshot, device, and thread |
| `reply_to_feedback` | Reply to the client on a request |
| `update_feedback_status` | Set `open`, `in_progress`, `done`, or `wont_do`, with an optional resolution note |

## Public API

Scripts and integrations can do the same with an [API key](https://www.dropl.io/docs/ai-and-api/api-keys) that has the Feedback scopes. Paths are relative to the [Public API](https://www.dropl.io/docs/ai-and-api/public-api) base URL, `https://www.dropl.io/api/v1`.

| Method and path | Scope | What it does |
| --- | --- | --- |
| `GET /sites/{siteId}/feedback` | `feedback:read` | A site's requests. Query: `status` (comma-separated, default `open,in_progress`), `type`, `page`, `limit` (default 50, up to 100), `offset` |
| `GET /feedback/{requestId}` | `feedback:read` | One request with its context and thread |
| `POST /feedback/{requestId}/replies` | `feedback:write` | Reply. Body: `{ "message": "..." }` |
| `PATCH /feedback/{requestId}` | `feedback:write` | Change the status. Body: `{ "status": "done", "resolutionNote": "..." }` |

`siteId` is the client site's `id` from `GET /sites`. Resolution notes can be up to 2000 characters. A key without the scope gets `INSUFFICIENT_SCOPE`.

List the open requests:

```bash
curl "https://www.dropl.io/api/v1/sites/SITE_ID/feedback?status=open,in_progress" \
  -H "Authorization: Bearer $DROPL_API_KEY"
```

Mark one done with a note:

```bash
curl -X PATCH "https://www.dropl.io/api/v1/feedback/REQUEST_ID" \
  -H "Authorization: Bearer $DROPL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"status": "done", "resolutionNote": "Changed the homepage heading to \"Fresh bread every morning\"."}'
```

## Troubleshooting

**The assistant is missing a permission (`INSUFFICIENT_SCOPE`).** The connection was approved before Feedback existed or without the Feedback permissions. Run `npx -y @dropl/mcp login` again and leave them ticked.

**The assistant can't find the element.** The page may have changed since the request, or the text is built from data. Ask it to reply to the client, or open the request in the dashboard and use the screenshot.

**The client didn't get an email.** Clients get an email when you reply or mark a request done. Status changes to **In progress** don't send one.

## Next steps

- [Install the Dropl script](https://www.dropl.io/docs/feedback/install): add the toolbar to your client's site.
- [Set up with AI](https://www.dropl.io/docs/ai-and-api/set-up-with-ai): connect the MCP server.
- [Public API](https://www.dropl.io/docs/ai-and-api/public-api): authentication, errors, and rate limits.

---

# Client sites and domains

Source: https://www.dropl.io/docs/client-sites/domains-and-embed-protection

> Save each client's website domains and, if you want, only let their videos and showcases load on those domains.

Each **client site** can keep a list of the website domains it belongs to. On its own, the list changes nothing: embeds keep working on any website. Turn on **embed protection** and the site's videos and showcases only load on those domains.

Only **Owners** and **Admins** can change site settings.

## Add a website when you create a site

1. Open **Settings → Sites**.
2. Under **Add a client site**, type the site name.
3. Optionally, type the client's website in **Website (optional)**, like `altahomes.com`.
4. Click **Add site**.

The domain shows under the site's name in the list. Embeds still work anywhere until you turn on protection.

## Open a site's settings

In **Settings → Sites**, click **Settings** next to the site, or open the **⋯** menu and choose **Site settings**. The settings panel has:

- **General:** the site's name.
- **Website domains:** the domains embeds are allowed on when protection is on.
- **Embed protection:** whether to limit embeds to those domains.
- **More for this site:** shortcuts to **Player settings**, **Clients**, and **Archive site**.

Click **Save changes** when you're done.

## Website domains

Type a domain and press **Enter** or click **Add**. You can paste a full link too: `https://www.AltaHomes.com/contact` is saved as `altahomes.com`.

- `example.com` also covers `www.example.com`.
- `*.example.com` covers every subdomain, like `shop.example.com`. It doesn't cover `example.com` itself, so add both if you need both.
- Domains with accents or non-Latin letters are saved in their encoded form (`bücher.example` becomes `xn--bcher-kva.example`).
- Each site can have up to 20 domains.

Some entries are refused, with a message saying why:

- `localhost` and IP addresses. Use **Allow localhost for testing** instead.
- Wildcards on shared hosting like `*.vercel.app`, `*.pages.dev`, or `*.netlify.app`. Those would let anyone's site on that host embed your media. Add the exact address, like `my-site.vercel.app`, or a wildcard under it, like `*.my-site.pages.dev`.

## Embed protection

Embed protection is off for every new site.

Turn on **Only allow embeds on these domains** to limit where the site's media loads:

- Videos and showcases embedded on a listed domain load as usual.
- On any other website, the embed shows "This video can't be played on this website." or "This showcase can't be shown on this website." instead.
- Dropl's own pages, like watch pages and the dashboard, always work.
- Inside a showcase, each video still follows its own embed setting. Videos use the site's setting unless they were given their own.

If protection is on and the list is empty, the panel warns you: embeds won't load on any website until you add a domain.

### Testing on your computer

Turn on **Allow localhost for testing** to let embeds load on `localhost`, `127.0.0.1`, and `[::1]` on any port while you build the site. It only matters while protection is on. Turn it off when the site goes live if you don't need it.

For preview deployments, add the preview's exact address (or a wildcard under your own project, like `*.my-site.pages.dev`) to **Website domains**.

## What protection doesn't do

Protection checks which website a browser says it's loading the embed from. That stops other websites from embedding your client's media. It isn't a password: anyone who can watch a video can still find a way to save it. To limit who can watch, use a video's **Private** or password settings.

Embeds inside sandboxed frames, or pages opened from a file on your computer, don't say which website they're on, so they're blocked while protection is on.

## Related

- [Getting started](https://www.dropl.io/docs/getting-started#add-more-client-sites)
- [Public API](https://www.dropl.io/docs/ai-and-api/public-api): `POST /v1/sites` takes the same `domain` field.
- [Set up with AI](https://www.dropl.io/docs/ai-and-api/set-up-with-ai)

---

# Set up with AI (Cursor, Claude Code)

Source: https://www.dropl.io/docs/ai-and-api/set-up-with-ai

> Connect Dropl to Cursor, Claude Code, or another MCP client so your AI assistant can set up collections, create showcases, upload media, and paste embed codes.

Dropl has an MCP server, `@dropl/mcp`. MCP is how AI coding assistants like Cursor and Claude Code use outside tools. With Dropl connected, your assistant can create a **client site** and a **showcase**, upload photos and videos from your project, and paste the embed code into the right page. It can also turn content that's hard-coded in your site into **collections** your client edits: see [Set up Collections with AI](https://www.dropl.io/docs/collections/set-up-with-ai).

It always plans first and asks you before it creates or uploads anything.

## What you need

- An AI assistant that supports MCP: Cursor, Claude Code, or another MCP client.
- Node.js 20.3 or later, because the server runs with `npx`.
- An **Owner** or **Admin** to approve the sign-in. Team members can set up their editor, but an owner or admin has to approve the connection.

## 1. Add the Dropl MCP server

### Cursor

Add this to `.cursor/mcp.json` in your project. If the file already lists servers, add the `dropl` entry next to them.

```json
{
  "mcpServers": {
    "dropl": {
      "command": "npx",
      "args": [
        "-y",
        "@dropl/mcp@latest"
      ]
    }
  }
}
```

### Claude Code

Run this in your project folder:

```bash
claude mcp add dropl -- npx -y @dropl/mcp@latest
```

### Other MCP clients

Add a stdio server named `dropl` with the command `npx` and the arguments `-y @dropl/mcp`.

After adding the server, restart or reload MCP servers in your editor so the Dropl tools show up.

## 2. Sign in

Run this in a terminal:

```bash
npx -y @dropl/mcp login
```

1. Your browser opens the **Connect an app** page. Sign in to Dropl if asked.
2. Check that the code on the page matches the one in your terminal, then click **Continue**.
3. Review the request. The app and device names are reported by the app itself, so anyone can set them: the code and the time are what to check.
4. Pick the **Account** to connect. Untick any permission you don't want to give, and limit the connection to some **Client sites** if you like.
5. Click **Approve**, then go back to your terminal or editor.

The code expires after 10 minutes. If it runs out, run the sign-in command again.

Approving creates an API key that acts as you. It shows up in **Settings → API keys** with the app's name, and you can revoke it there any time.

> **Warning:** Only approve a sign-in you just started yourself. Dropl will never ask you for this code by email, chat, or phone. If you didn't start it, click **Deny**.

### Use an API key instead

Owners and admins can create a key in **Settings → API keys** and set it as `DROPL_API_KEY` in the MCP server's environment (the `env` block in `.cursor/mcp.json`, or `-e` for Claude Code). Never paste a key into a chat or commit it. See [API keys](https://www.dropl.io/docs/ai-and-api/api-keys).

## 3. Copy a prompt from the dashboard

1. Open **Media** or **Collections** and click **Set up with AI**. Owners and admins also find it on **Settings → Sites**.
2. Under **Connect Dropl to your editor**, copy the snippet for your editor if you haven't added Dropl yet.
3. Under **Copy a prompt**, pick what you want done:
   - **Make content editable (Collections):** describe what your client edits, or pick an example, and the assistant builds the collections, imports the content, and wires up the site.
   - **Migrate an existing gallery:** move a gallery that's hard-coded in the project into a showcase.
   - **Upload a folder as a showcase:** turn a folder of photos and videos into a new showcase.
   - **Add a video player to a page:** upload a video and put the player where it should play.
   - **Create a new client site:** add a site for this project.
4. Fill in the details. The client site is filled in from the site you have open.
5. Check the preview and click **Copy prompt**, then paste it into your assistant's chat.

Prompts never include API keys or passwords.

## What the assistant does

1. Calls `whoami` to confirm which account and permissions it has.
2. Looks through your project for the gallery, folder, or page you described.
3. Shows you a plan: the client site, the showcase and its categories, and how many files it will upload with their total size.
4. Waits for your confirmation.
5. Finds or creates the client site, creates the showcase, turns folders into categories, and uploads the files with alt text (a short description of each photo for screen readers and search). Uploads return each file's Dropl id, so it fixes alt text or categories afterwards by id instead of uploading again.
6. Gets the embed code from Dropl with `get_embed_code` and pastes it into the page. It never writes the snippet by hand.
7. Runs your project's build and fixes anything it broke.
8. Reports what it did, with links to your dashboard.

The Dropl tools it uses:

| Tool | What it's for |
| --- | --- |
| `whoami` | The connected account, your role, and the key's permissions |
| `list_sites`, `create_site` | Find or add a client site |
| `list_showcases`, `get_showcase`, `create_showcase` | Find, inspect, or add a showcase |
| `create_category`, `tag_items` | Add showcase categories and put items in them |
| `list_showcase_items`, `update_items` | List a showcase's items with their alt text and categories, and change many at once |
| `upload_photos`, `upload_videos` | Upload files from your computer, with alt text and categories per photo, and get each file's id back |
| `add_videos_to_showcase` | Add uploaded videos to a showcase |
| `get_embed_code` | The snippet to paste into a page |
| `get_usage` | Storage and delivery used so far |
| `plan_migration` | Count and size what would be uploaded, without changing anything |
| `list_collections`, `get_collection_schema` | Find collections and read their current fields |
| `plan_collections`, `apply_collection_plan` | Preview, then apply, new or changed collections |
| `add_collection_items`, `list_collection_items` | Import and look up collection items |
| `get_collection_code` | TypeScript types and a Next.js example for a collection |
| `undo_collection_change` | Undo the most recent schema change |

## Confirm before anything is uploaded

The prompts tell your assistant to show a plan and wait for your explicit go-ahead before it creates anything in Dropl or uploads a file. Read the plan: check the client site, the number of files, and the total size. Say no, or ask for changes, if anything looks off.

Uploads count toward your plan's storage, and everything the assistant creates shows up in **Media** and **Collections** like anything you add yourself.

## Troubleshooting

**The Dropl tools don't show up.** Check that `.cursor/mcp.json` is valid JSON, or run `claude mcp list` in Claude Code. Make sure Node.js 20.3 or later is installed, then restart or reload MCP servers.

**"That code is invalid or has expired."** Codes last 10 minutes and work once. Run `npx -y @dropl/mcp login` again for a new one.

**"An owner or admin needs to approve this."** You're a team member. Ask an owner or admin of your account to approve the sign-in.

**The assistant says the key is invalid (`INVALID_API_KEY`).** The key was revoked or expired, or the person who approved it is no longer an owner or admin. Sign in again.

**The assistant is missing a permission (`INSUFFICIENT_SCOPE`).** The connection was approved without it. Sign in again and leave that permission ticked.

**It can't create a client site (`SITE_RESTRICTED_KEY`).** Connections limited to some client sites can't add new ones. Create the site in **Settings → Sites**, or sign in again with all client sites allowed.

**An upload was rejected.** Check the file against the [upload limits](https://www.dropl.io/docs/ai-and-api/public-api#upload-limits).

## Next steps

- [API keys](https://www.dropl.io/docs/ai-and-api/api-keys): scopes, site limits, expiry, and revoking access.
- [Public API](https://www.dropl.io/docs/ai-and-api/public-api): call Dropl from your own scripts.
- [Getting started](https://www.dropl.io/docs/getting-started): the dashboard basics.

---

# API keys

Source: https://www.dropl.io/docs/ai-and-api/api-keys

> Create, limit, and revoke the keys that let AI assistants and scripts work in your Dropl account.

An API key lets a tool work in your Dropl **account** without your password: an AI assistant connected through the [Dropl MCP server](https://www.dropl.io/docs/ai-and-api/set-up-with-ai), or your own script calling the [Public API](https://www.dropl.io/docs/ai-and-api/public-api).

## Who can create keys

Only **Owners** and **Admins** can create and revoke keys. Team members and clients can't.

A key acts as the person who created it, limited to the scopes and client sites picked for it. It stops working if that person is removed from the account or is no longer an owner or admin.

## Create a key

1. Open **Settings → API keys** and click **Create API key**.
2. Enter a **Name** that says where the key is used, like "Deploy script".
3. Pick the **Scopes** the tool needs. All are ticked to start; untick what it doesn't need.
4. Under **Client sites**, keep **All client sites** or choose **Only the sites I pick**.
5. Choose when it **Expires**: never, or in 30, 90 or 365 days.
6. Click **Create key**, then copy the key.

Each account can have up to 50 active keys.

Using Cursor or Claude Code? You don't need to create a key by hand. The [browser sign-in](https://www.dropl.io/docs/ai-and-api/set-up-with-ai#2-sign-in) creates one for you, named after the app.

## Scopes

| Scope | Allows |
| --- | --- |
| `sites:read` | See your client sites |
| `sites:write` | Create client sites |
| `showcases:read` | See showcases and their categories |
| `showcases:write` | Create and edit showcases, categories, and tags |
| `videos:read` | See videos in your library |
| `media:write` | Upload photos and videos |
| `embed:read` | Get embed codes |
| `usage:read` | See storage and delivery usage |
| `collections:read` | See collections, their fields, and items (drafts included) |
| `collections:write` | Add, edit, reorder, and delete collection items |
| `collections:schema` | Create collections and change their fields (structure) |
| `feedback:read` | See website change requests from clients, with their context and replies |
| `feedback:write` | Reply to change requests and update their status |

A request that needs a scope the key doesn't have fails with `INSUFFICIENT_SCOPE`.

## Limit a key to some client sites

A key limited to some client sites only sees and changes those sites. It can't create new client sites; that fails with `SITE_RESTRICTED_KEY`.

Use a site-limited key when a tool only works on one client's website.

## You only see a key once

The full key is shown once, right after you create it. Copy it then: Dropl stores only a hash of it and can't show it again. Afterwards the list shows just the start of the key, like `dropl_live_ab12…`.

Lost a key? Revoke it and create a new one.

## The key list

**Settings → API keys** lists every key with its scopes, client sites, who created it, when it was created, last used, and expires, and whether it's active, expired, or revoked. Keys created by a browser sign-in show the app's name.

## Revoke a key

1. Open **Settings → API keys**.
2. Open the key's **⋮ menu** and click **Revoke**.
3. Confirm with **Revoke key**.

Anything using the key stops working right away. Revoked keys stay in the list for 30 days so you can see what was cut off.

## When keys stop working

A key is refused with `INVALID_API_KEY` when:

- It was revoked.
- It expired.
- The person who created it was removed from the account or is no longer an owner or admin.

## Keep keys safe

- Never paste a key into an AI chat, email, or support ticket.
- Never commit a key to a repository. Keep it in an environment variable or your host's secret settings, and make sure files like `.env` are in `.gitignore`.
- Use one key per tool, with only the scopes and sites it needs, so you can revoke one without breaking the others.
- If a key leaks, revoke it right away.

## Next steps

- [Set up with AI](https://www.dropl.io/docs/ai-and-api/set-up-with-ai): connect Cursor or Claude Code.
- [Public API](https://www.dropl.io/docs/ai-and-api/public-api): authentication, errors, and limits.

---

# Public API

Source: https://www.dropl.io/docs/ai-and-api/public-api

> Call Dropl from your own scripts and servers. Base URL, authentication, scopes, errors, idempotency, rate limits, and upload limits.

The Public API lets your scripts and servers do what the [Dropl MCP server](https://www.dropl.io/docs/ai-and-api/set-up-with-ai) does: work with client sites and showcases, upload photos and videos, and get embed codes.

It's for server-to-server use: it doesn't support calls from web pages in a browser (no CORS), and a key in front-end code would be visible to anyone. Keep keys on your server.

## Base URL

```text
https://www.dropl.io/api/v1
```

Every path below is relative to it.

## Authentication

Send an [API key](https://www.dropl.io/docs/ai-and-api/api-keys) as a Bearer token:

```bash
curl https://www.dropl.io/api/v1/me \
  -H "Authorization: Bearer $DROPL_API_KEY"
```

`/me` works with any scope and returns the account, the person the key acts as, their role, and the key's scopes and client sites. It's a good first call to check a key.

## Scopes

Each endpoint needs one scope. A key without it gets `INSUFFICIENT_SCOPE`, and the message names the missing scope. See the [list of scopes](https://www.dropl.io/docs/ai-and-api/api-keys#scopes).

Keys limited to some client sites only see those sites.

## Endpoints

A few common ones:

| Method and path | Scope | What it does |
| --- | --- | --- |
| `GET /me` | Any | The account, user, role, and key |
| `GET /sites` | `sites:read` | Client sites the key can reach |
| `POST /sites` | `sites:write` | Create a client site |
| `POST /sites/{siteId}/showcases` | `showcases:write` | Create a showcase |
| `GET /showcases/{showcaseId}/embed` | `embed:read` | Embed code for a showcase and each category |
| `GET /videos/{videoId}/embed` | `embed:read` | Embed code for a video |
| `GET /collections/{collectionId}/schema` | `collections:read` | A collection's fields, version, and generated TypeScript |
| `POST /sites/{siteId}/collections/plan` | `collections:schema` | Preview (default) or apply new or changed collections |
| `POST /collections/{collectionId}/items/bulk` | `collections:write` | Add up to 500 items, with errors for each item |

Websites read published collection items without a key: see [Show collections on your website](https://www.dropl.io/docs/collections/website-api).

The [OpenAPI document](https://www.dropl.io/api/v1/openapi.json) lists every endpoint with its request and response schemas. Load it into your API client or code generator.

## Errors

Errors return a JSON body with a stable `code`, a readable `message`, and `fieldErrors` when specific fields are wrong:

```json
{
  "error": {
    "code": "VALIDATION_FAILED",
    "message": "Please check the highlighted fields.",
    "fieldErrors": { "name": ["Enter a name."] }
  }
}
```

Codes specific to API keys:

| Status | Code | Meaning |
| --- | --- | --- |
| 401 | `INVALID_API_KEY` | The key is missing, unknown, revoked, or expired, or its creator is no longer an owner or admin |
| 403 | `INSUFFICIENT_SCOPE` | The key doesn't have the scope this endpoint needs |
| 403 | `SITE_RESTRICTED_KEY` | Keys limited to some client sites can't create client sites |
| 409 | `IDEMPOTENCY_KEY_IN_PROGRESS` | The first request with this `Idempotency-Key` is still running |
| 422 | `IDEMPOTENCY_KEY_REUSED` | This `Idempotency-Key` was used for a different request |

Other endpoints return the same codes as the dashboard, like `VALIDATION_FAILED`.

## Idempotency

Endpoints that create things accept an `Idempotency-Key` header, so a retry after a timeout doesn't create a second client site or showcase. The OpenAPI document marks which ones.

- Use a unique value per operation, like a UUID, up to 255 characters.
- Sending the same key and the same request again within 24 hours returns the first response. Replayed responses carry an `Idempotent-Replayed` header.
- Reusing a key for a different request fails with `IDEMPOTENCY_KEY_REUSED`.

## Rate limits

Each key can make up to 600 requests per minute, across every endpoint. Over the limit, requests get HTTP 429: wait a moment and retry.

## Upload limits

- **Videos:** up to **20 GB** each.
- **Photos:** JPEG, PNG, WebP, AVIF or HEIC, up to **20 MB** each and **100** per request.

Your plan limits total storage and monthly delivery. See [Pricing](https://www.dropl.io/pricing).

## Sign-in for your own tools

Building a command-line tool? Instead of asking people to paste a key, use the same browser sign-in as the MCP server (the OAuth device flow):

1. `POST /auth/device` returns a `user_code` and a `verification_uri_complete`. Show the code and open the link.
2. The person checks the code and approves on the **Connect an app** page.
3. Poll `POST /auth/device/token` every 5 seconds until it returns an `access_token`, which is a new API key.

The code expires after 10 minutes. Details are in the OpenAPI document.

## Next steps

- [API keys](https://www.dropl.io/docs/ai-and-api/api-keys): create and manage keys.
- [Set up with AI](https://www.dropl.io/docs/ai-and-api/set-up-with-ai): let Cursor or Claude Code do this for you.

---

# Dropl MCP

> Create client-editable photo and video galleries from Cursor or Claude Code, then embed them.

Dropl MCP lets AI coding agents set up Dropl for client websites: create client sites and showcases (embeddable photo and video galleries), upload whole folders of media with categories, fetch embed code for HTML, Next.js, WordPress, Webflow, and Framer, manage collections like menus, inventory, and events, and work through client feedback by fixing it in code, replying, and marking it done. Clients then update their own photos and videos from a phone, without a CMS.

Package: [@dropl/mcp](https://www.npmjs.com/package/@dropl/mcp).

## Install

Cursor (`.cursor/mcp.json`):

```json
{
  "mcpServers": {
    "dropl": {
      "command": "npx",
      "args": [
        "-y",
        "@dropl/mcp@latest"
      ]
    }
  }
}
```

Claude Code:

```sh
claude mcp add dropl -- npx -y @dropl/mcp@latest
```

Then sign in once (opens the browser):

```sh
npx -y @dropl/mcp login
```

## Tools

### Galleries

- `plan_migration`: Scans a local folder without uploading and proposes a plan for you to confirm.
- `upload_photos`: Uploads local photos into a showcase, with alt text and categories per photo. Returns each file's id. Dry run first; resumable.
- `list_showcases`: Lists a client site's showcases, newest first.
- `create_showcase`: Creates an embeddable photo and video gallery after you confirm.
- `get_showcase`: Summarizes a showcase: settings, items by status, categories, photos missing alt text, and failed items.
- `list_showcase_items`: Pages through a showcase's items with their ids, the local files they came from, alt text, and categories.
- `update_items`: Sets alt text and adds or removes categories on many items at once, by the ids uploads return. No re-upload.
- `update_showcase`: Changes a showcase's title, layout, filter tabs, or page size.
- `create_category`: Adds a filter tab, reusing one that already exists.
- `tag_items`: Adds or removes categories on showcase photos and videos, by the ids uploads return.
- `get_embed_code`: Returns the official embed for a video or showcase, and where to paste it (HTML, React/Next.js, WordPress, Webflow, Framer).

### Projects

- `list_projects`: Lists a portfolio showcase's projects with their details, categories, and photos.
- `create_project`: Adds a project with its title, location line, description, details, and categories.
- `update_project`: Changes a project's text, link name, cover photo, details, or categories.
- `reorder_projects`: Puts projects in a new order on the website.
- `reorder_project_items`: Reorders the photos and videos inside one project.
- `get_project_details`: Reads the custom project details (like square footage or year), including dashboard edits.
- `plan_project_details`: Dry run: previews changes to the custom project details as a plain-text diff. Nothing is saved.
- `apply_project_details`: Saves the details change you approved. Removing values needs explicit confirmation; a stale plan is refused.

### Video

- `upload_videos`: Uploads local videos to a client site's library and returns each file's id. Dry run first; resumable.
- `list_videos`: Lists videos in a client site's library, with an optional title search.
- `add_videos_to_showcase`: Adds existing library videos to a showcase.

### Collections

- `list_collections`: Lists a client site's collections with item counts, when the site last read each one, and the plan's limits.
- `get_collection_schema`: Reads a collection's current fields, including edits made in the dashboard, so changes start from the real state.
- `plan_collections`: Dry run: previews creating or changing up to 10 collections and returns a plain-text diff. Nothing is saved.
- `apply_collection_plan`: Applies the plan you approved. Destructive changes need explicit confirmation; a collection edited since the plan is refused.
- `add_collection_items`: Bulk-imports items, like a list hard-coded in your site, with per-item errors. Previews first; saving needs your confirmation.
- `list_collection_items`: Lists items, drafts included, with search, filters, sorting, and paging.
- `get_collection_code`: Returns TypeScript types and a Next.js fetch example generated from the current fields, plus the public items URL.
- `undo_collection_change`: Undoes the most recent schema change after you confirm, when no data written since would be lost.

### Feedback

- `list_feedback`: Lists the change requests a client left on their site, newest first; open and in progress by default.
- `get_feedback`: Reads one request in full: page, element, current and requested text, device, screenshot, and the thread.
- `reply_to_feedback`: Replies to the client in the request's thread; they get it by email. Used to ask instead of guessing.
- `update_feedback_status`: Sets open, in progress, done, or won't do, with a short note. Marking done emails the client.

### Account and usage

- `whoami`: Shows the connected account, user, role, and API key, to check the connection.
- `list_sites`: Lists the client sites the key can reach, with domains and the plan's site allowance.
- `create_site`: Creates a client site after you confirm. Safe to retry.
- `get_usage`: Shows storage and bandwidth used against the plan's limits.
