Embed brew recipes on your site
Add interactive recipe cards to any website with two lines of HTML, or use our REST API to build custom integrations.
Two lines. Any website.
<!-- 1. Include the BrewMark widget script --> <script src="https://brewmark.io/embed/widget.js"></script> <!-- 2. Place this where you want the widget --> <div data-brewmark-widget="your-roaster-slug"></div>
The widget script auto-initializes on page load. Each data-brewmark-widget element becomes an interactive coffee card rendered in a Shadow DOM for full CSS isolation. No API key required.
Widget options
Customize the widget with HTML data attributes. No API key required—all public endpoints are open and CORS-enabled.
data-brewmark-widgetstringrequiredYour roaster slug (e.g. "onyx-coffee-lab"). Find this in your Roaster Portal URL.
data-theme"light" | "dark"Color theme. Light uses warm paper tones, dark uses deep brown. Default: "light".
data-layout"card" | "badge" | "inline"Display layout. Cards show full detail, badges are compact pills, inline is a simple list. Default: "card".
data-coffeestringFilter to a single coffee by slug (e.g. "southern-weather"). Omit to show all coffees.
data-accent-color"#rrggbb"Custom accent color as hex. Overrides the roaster's saved accent color. Default: "#1D3557".
data-border-radius0-24Border radius in pixels for cards and the widget container. Default: 4.
data-show-powered-by"true" | "false"Show or hide the "powered by BrewMark" badge. Premium roasters can hide it via their portal settings.
Widget Features
Programmatic Re-initialization
If you dynamically add widget elements after page load (e.g., in a single-page app), call the init function manually:
// After adding new data-brewmark-widget elements to the DOM window.__brewmarkWidgetInit();
Iframe Embed (Alternative)
If you prefer an iframe over the JS widget, use the iframe embed URL directly. Supports the same theme, layout, and coffee parameters as query strings.
<iframe src="https://brewmark.io/embed/your-roaster-slug?theme=light&layout=card" width="420" height="400" frameborder="0" />
Platform Guides
- Edit product description
- Click "Show HTML"
- Paste embed code
- Add Custom HTML block
- Paste embed code
- Preview and publish
- Add Code block
- Paste embed code
- Uncheck "Display Source"
Try it out
Toggle theme and layout options to see how the widget looks on your site. The embed code updates automatically.
<!-- 1. Include the widget script --> <script src="https://brewmark.io/embed/widget.js"></script> <!-- 2. Place widget where you want it --> <div data-brewmark-widget="onyx-coffee-lab"></div>
Public endpoints
Looking for the full API reference with auth, brew logs, user profiles, and all endpoints? View the complete API documentation →
All public endpoints are open and require no API key. Requests return JSON and support CORS for cross-origin use. Base URL: https://brewmark.io
/api/embed/{roasterSlug}/{coffeeSlug}CORS5 minFetch all brew recipes for a specific coffee. Returns roaster info, coffee details, and an array of recipes across brew methods. Best for embed widgets.
roasterobject{ name, slug }coffeeobject{ name, slug, roastLevel, flavorNotes[] }recipesarray{ method, doseGrams, waterGrams, ratio, waterTempF, grindSize, brewTimeSeconds, notes, isDefault }curl https://brewmark.io/api/embed/onyx-coffee-lab/southern-weather
{
"roaster": { "name": "Onyx Coffee Lab", "slug": "onyx-coffee-lab" },
"coffee": {
"name": "Southern Weather",
"slug": "southern-weather",
"roastLevel": "Light",
"flavorNotes": ["Blueberry", "Chocolate", "Citrus"]
},
"recipes": [
{
"method": "V60",
"doseGrams": 20,
"waterGrams": 320,
"ratio": 16,
"waterTempF": 205,
"grindSize": "Medium-Fine",
"brewTimeSeconds": 210,
"isDefault": true
}
]
}/api/embed/{shareId}Fetch a single user recipe by its share ID. Automatically records an impression event for embed analytics.
namestringRecipe namemethodstringPrimary brew methoddoseGramsnumberCoffee dose in gramswaterGramsnumberWater amount in gramsrationumberWater-to-coffee ratiobrewTimeSecondsnumber|nullTotal brew timewaterTempFnumber|nullWater temperature (Fahrenheit)grindSettingstringGrind size descriptioncoffeeNamestring|nullAssociated coffee nameroasterstring|nullRoaster namebrewMethodsarray|nullAlternative brew methods with parameters/api/roastersList all roasters. Supports search and pagination.
searchstringFilter by roaster namepagenumberPage number (default: 1)limitnumberResults per page (default: 20)curl "https://brewmark.io/api/roasters?search=onyx&limit=5"
{
"roasters": [
{ "id": 1, "name": "Onyx Coffee Lab", "slug": "onyx-coffee-lab", ... }
],
"total": 1,
"page": 1
}/api/roasters/{slug}Get a single roaster by URL slug. Returns roaster profile details.
slugstringURL-safe roaster identifier/api/roasters/{slug}/coffeesList all coffees from a roaster. Supports filtering by roast level and cursor-based pagination.
roastLevelstringFilter: Light, Medium, DarkcursorstringPagination cursorlimitnumberResults per page (default: 20)/api/roasters/{slug}/recipesList community-submitted recipes for a roaster's coffees.
cursorstringPagination cursorlimitnumberResults per page (default: 20)/api/recipes/{id}Get a single recipe by numeric ID. Returns full recipe detail including grinder, brewer, and filter information.
/api/recipesSearch and list recipes. Returns paginated results.
searchstringSearch by recipe name or coffeemethodstringFilter by brew method/api/coffeesList and search coffees across all roasters.
searchstringSearch by coffee or roaster name/api/brew-methodsList all available brew methods (V60, AeroPress, Chemex, French Press, etc.).
/api/healthHealth check endpoint. Returns service status, uptime, and database latency.
curl https://brewmark.io/api/health
{
"status": "ok",
"timestamp": "2026-03-12T20:00:00.000Z",
"uptime": 86400,
"checks": { "database": { "status": "ok", "latencyMs": 12 } },
"version": "1.0.0"
}Built-in tracking
The embed widget automatically tracks three event types. View your analytics in the Roaster Portal.
IMPRESSIONautomaticFired when the recipe card loads on a page. Includes the HTTP referer for source tracking.
CLICKautomaticFired when a user clicks the recipe link to view the full recipe on BrewMark.
METHOD_SWITCHautomaticFired when a user switches between brew method tabs. Records which method was selected.
If you need to fire events from your own code, use the tracking endpoints directly:
// Track a click fetch("https://brewmark.io/api/embed/track-click", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ shareId: "roaster-slug/coffee-slug" }) })
Rate limits, CORS, and caching
Rate Limits
Public API endpoints are rate-limited per IP. Embed endpoints have generous limits for production widget use. If you hit a rate limit, you'll receive a 429 Too Many Requests response with a Retry-After header.
CORS
Embed API endpoints set Access-Control-Allow-Origin: * so the widget works from any domain. The embed script handles CORS preflight automatically.
Caching
Roaster/coffee embed responses are cached for 5 minutes at the edge with a 10-minute stale-while-revalidate window. When you update recipes in the Roaster Portal, changes appear in embeds within 5 minutes.
Ready to get started?
Generate your embed code in seconds, or claim your roaster profile to manage recipes and track analytics.