Show collections on your website
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.
https://www.dropl.io/api/public/collections/m7qk2xr9/itemsOnly 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
{
"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:
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: 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 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 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.

