Updated · 13 min read
Stripo, natively — connect your account, sync your modules, compose emails through the API
If you've built more than two or three emails in Stripo, you know the loop. Build something pretty in Stripo's editor. Export the HTML. Paste it into Claude to reword the headline or assemble a new variant. Paste the result back into Stripo to send. Four manual steps. Half an hour of clipboard tennis for what should be a single conversation. The native Stripo integration ends the tennis match: Orbit reads your Stripo modules directly, Claude composes new emails from them inside chat, and the assembled email lands back in your Stripo workspace as an editable artifact. Architecture and the two non-obvious things you'll hit during setup, below.

By Justin Williames
Founder, Orbit · 10+ years in lifecycle marketing
If you're new here: what Stripo is, and why this integration exists
If you build emails in Stripo, you almost certainly have a module library — a collection of saved blocks you drag into new emails so you're not rebuilding the header every single time. That library is the asset Orbit cares about. Once it's connected, Claude can read your modules, classify them, compose new emails by stitching them together in the right order, and push the finished result back into Stripo for your team to edit and send.
The integration replaces what most teams do today: copy the HTML out of Stripo by hand, paste it into Claude, ask Claude to tweak it, paste the result back into Stripo. That paste-driven flow is fine for a one-off — it's how Orbit's supported Stripo until now — but if Stripo is your daily email production tool, it gets old fast. The native integration closes the loop.
The whole loop, in one animation
The picture before the architecture. Three phases play in sequence: Claude reads your brief and picks modules from your synced library, the assembled HTML is composed (deduped CSS, preserved esd-custom-block-id attributes — the hidden tags Stripo uses to track which block is which), and the rendered preview lands as an editable email in your Stripo workspace. Plays once when you scroll into view, then loops.
The rest of this guide unpacks what's happening in each phase, what you set up once and never again, and the two non-obvious things that bite everyone the first time.
Two ways to use Stripo with Orbit — and how to pick
Orbit's supported Stripo for a while, but only one way: the paste-driven flow. You'd copy the HTML of an email out of Stripo, run a tool called orbit_learn_email_template, and Orbit would reverse-engineer the modules from the raw HTML. The native integration sits alongside that flow, not on top of it. Both still work. They suit different jobs.
| Approach | When it's the right tool | When it isn't |
|---|---|---|
| Paste-driven (orbit_learn_email_template) | One-off — a single template you want Claude to understand and edit. No recurring relationship with Stripo. | Modules change in Stripo and your local copy goes stale immediately. You're doing this every week. |
| Native API (orbit_setup_stripo and friends) | Stripo is your daily email production tool. You want every saved module reflected in Orbit, and emails composed in chat to land back in your Stripo workspace as editable artifacts. | You don't have a paid Stripo plan that includes API access (Business tier or above). |
Rough rule: native integration when Stripo is your source of truth and your destination. Paste flow when you're tweaking one email Claude has never seen before. If you don't have a paid Stripo plan, the paste flow is your only option — and it's perfectly serviceable.
Setup gotcha #1 — there are two sets of credentials, and they are not interchangeable
Stripo has two different APIs with two different sets of keys. The keys you use for the embedded editor (Plugin keys) do not work for the API that lists your modules (REST keys). Every team trips on this the first time.
Here's the bit nobody tells you upfront. Stripo offers two ways for outside tools to talk to it, and each has its own login. They live in different parts of the Stripo settings UI, and you cannot swap one for the other.
| Credential | Where to find it | What it actually does |
|---|---|---|
| Plugin ID + Secret Key | Stripo: Account → Plugin | Mints short-lived tokens (JWTs — JSON Web Tokens, used for browser-side auth) that let Stripo's editor open inside other tools. Orbit checks these to confirm Plugin auth works, but it isn't what does the heavy lifting. |
| REST API token (per project) | Stripo: Settings → Workspace → Projects → REST API | The actual key Orbit uses for everything that matters: pulling your module library (findmodules), creating emails (generateemail). Without this token, the integration cannot read or write a single thing. |
Orbit's setup tool — orbit_setup_stripo — runs both checks for you and tells you exactly which credentials are present, which work, and where to click in Stripo to fix the broken ones. The output is a markdown checklist with ticks (✅ / ⬜) that updates each time you re-run it. If Plugin auth works but REST throws a 401 (the HTTP code for "not authorised"), the message points you straight at the REST settings page.
Setup gotcha #2 — the one-off Stripo template that makes the whole thing work
Stripo's API was designed to fill in templates, not build them from scratch. Think of it like a picture frame waiting for a photo — Stripo provides the frame, Orbit slides the photo in. That design choice is genuinely sensible from Stripo's side, but it has one consequence you have to know about up front.
The endpoint Orbit uses to push composed emails back into Stripo (/emailgeneration/v1/email) does not create an email out of nothing. It needs a pre-existing template — what Stripo calls a master template — with a designated empty zone Orbit's composed HTML drops into.
So before any of this works end-to-end, you do a one-time setup in Stripo: create a new template, name it something obvious like Orbit Master, drop a Structure block onto the canvas, and in the right-hand panel mark that block as the Generation area — Stripo's term for "this is where new content goes." Save it. Copy the template ID from the URL into Orbit's extension settings. Done. From that moment on, every email Orbit composes flows into that template's generation area as a fresh editable email in your Stripo workspace.
It's a one-time tax. Trade-off is fine in practice: one template setup, then every future composition flows through it cleanly with no further plumbing.
What Orbit does with your modules — the design-system brief
Once orbit_sync_stripo_modules has pulled your library down — every saved module from Stripo, with its HTML and Stripo's own classification tags — the next move is orbit_document_stripo_design_system. This produces a single markdown document — saved at ~/Orbit/outputs/stripo-design-system/ — that catalogues your modules and infers the rules of your design system from them.
The doc has four sections worth knowing about. Each one is something Claude reads before composing, so they directly shape the emails you get back.
Module inventory. Every module, sorted by what kind of block it is — header, hero, content, footer. Classification is automatic, using Stripo's own taxonomy: a Stripo header stays a header in Orbit, banners become heroes, content_canvas becomes content, footer stays a footer. No guesswork.
Brand tokens. The visual values Orbit detects across your modules — button colour, text colour, font family, button padding. Orbit reports the consensus value (the one most modules use) and any outliers, so a single rogue module using a different button colour gets flagged rather than buried.
Inferred composition rules. What Orbit notices about how your emails are put together. If all your headers are full-width STRIPE blocks (Stripo's term for an edge-to-edge horizontal section), the doc says so. If every footer contains the same Liquid variables — unsubscribe, view-in-browser, etc. (Liquid is the templating language most ESPs use to inject personalised values into emails) — the doc names them. These become rules Claude honours when composing.
Risks and gaps. The things Orbit thinks are quietly wrong with your library. Two modules with the same name in the same category (the kind of thing that causes "wrong module picked" bugs at compose time). Footers with no Liquid variables (suspicious — usually means a missing unsubscribe link). Modules that fell into Stripo's other classification because they weren't tagged. Real, specific flags rather than vague warnings.
The brief is the load-bearing document for everything that happens next. Claude reads it before any compose call, which means the emails Orbit produces respect the patterns you've already set up in Stripo rather than inventing new ones.
One honest caveat about the inspection step. orbit_inspect_stripo_module_bindings tells you what dynamic variables a module has registered — headline, image, CTA URL — and that's genuinely useful for catching structural gaps (a module missing a CTA variable, an orphan class with nothing pointing at it). What it cannot tell you is whether those variables actually substitute at compose time. Registration in the editor and substitution in a compiled email are two different facts. The next section is about how to verify the second one, because the failure modes between them are silent.
The premise underneath all of this — that a properly modular Stripo setup compounds in productivity terms over time — is well-evidenced. Jstn Consulting documented cutting their email production time substantially after committing to a modular Stripo system.Source · StripoCase study: how Jstn Consulting cut email production time with Stripo's modular designOperator case study on the productivity impact of building emails from a curated module library rather than from scratch — the same compounding effect Orbit's native integration leans into.stripo.email/blog/case-study-how-jstn-consulting-cut-email-production-time-with-stripos-modular-design Orbit's native integration is, in effect, a force multiplier on the same pattern: once your module library is good, every new email is an act of composition rather than construction.
Verifying that bindings actually substitute — the probe-email recipe
Registering a Smart Element variable in Stripo's Data tab is the first move, not the last. The editor accepts registrations that point at classes that don't exist in the module. The compose tool accepts slot values for variables that will silently no-op every send. The only honest verification is to push a probe email with sentinel values and grep the rendered HTML.
Stripo's editor lets you bind variables — module slots Orbit can fill at compose time — using either a Block-Type target (this CTA button, that image block) or a CSS Selector (any element matching .esd-gen-headline). The Block-Type targeting is editor-only. It doesn't survive the REST API round-trip, which means it never substitutes in API-composed emails. CSS-Selector targeting is the only mode that works through Orbit. That's the famous footgun and the inspector catches it.
What the inspector doesn't catch — and what this section is really about — are two silent failure modes where the variable looks fine on paper but substitution never lands.
Selector without target. A variable is registered with a CSS selector that doesn't match any element in the module's source HTML. Stripo accepts the registration. orbit_compose_stripo_email accepts the slot value. The compiled email contains the module's default content. Every send. No error anywhere. A real example from a recent verification pass: a max-prominence CTA module had p_image registered against .esd-gen-image, but the <img> element in the module's HTML never had that class on it. The default hero image went out on every campaign for weeks before anyone spotted it.
Class on wrapper, text on child. The selector matches — but it matches a wrapper element whose direct text node is empty. The visible copy lives in nested children. Stripo's substitution dutifully writes the new inner text to the wrapper, the rich-content children stay untouched, and the email still ships with the original copy. From the operator's seat, indistinguishable from the first failure mode: the variable is "set," the value was "passed," the email is still wrong.
Both modes share one tell. You cannot detect them by reading the registration alone. You have to push an email with a sentinel value and check the compiled HTML to see whether the sentinel actually appears.
The preview-API endpoint is the verification surface. When orbit_compose_stripo_email runs with push: true, the response includes a previewUrl like https://viewstripo.email/<uuid>. That URL serves a heavy Angular app that loads the rendered email into iframes asynchronously — fine for humans, brittle to scrape. Behind it, Stripo runs a JSON endpoint that returns the fully compiled HTML in a single html field: https://viewstripo.email/cabinet/stripeapi/v2/preview/web/<uuid>. Fetch it, parse the JSON, grep the html for your sentinels. Milliseconds. No headless browser.
The probe-email recipe, end to end:
1. Run orbit_sync_stripo_modules to refresh the local mirror against your live Stripo library.
2. Run orbit_inspect_stripo_module_bindings <module_id> on each module you care about. That gives you the list of registered variables, the esd-gen-* class hooks present in the HTML, and a top_level_link_field flag for the wrapper-link edge case.
3. Push a probe email through orbit_compose_stripo_email with push: true and unique sentinel values for every variable on the module. Convention worth adopting: text variables get a string like PROBE-<moduleId>-<varName>, URL/href/src variables get https://probe.test/<moduleId>/<varName>. Unique strings, easy to grep, impossible to confuse with real content.
4. Extract the UUID from the returned previewUrl and fetch https://viewstripo.email/cabinet/stripeapi/v2/preview/web/<uuid>. Parse the JSON. Grep the html field for every sentinel.
5. Any sentinel that isn't in the compiled HTML is a silent no-op — a broken binding. Open the module in Stripo's Design tab, find the element the variable is meant to fill, and either add the missing class hook to the right element or move the class off the wrapper and onto the actual text-bearing child. Re-probe. Repeat until every sentinel shows up.
Five minutes per module the first time you do it, less than a minute on repeats. That cost beats the alternative — "why did nobody get the new offer image?" — by a wide margin.
The deeper point: registration is necessary, not sufficient. The success state for a Smart Element variable isn't "it appears in the inspector" — it's "a probe sentinel pushed through it lands in the compiled HTML." Anything short of that is a guess. Probe once per module when you build it, re-probe after any Stripo-side edit to the module's structure, and trust the compiled output rather than the editor's green ticks.
The compose loop in chat — plan, preview, approve, push
When the compose tool runs, it doesn't just return raw HTML — it returns the HTML wrapped in a directive that tells Claude to render it as a visual artifact immediately. You see the actual rendered email in chat, not a description of what you'll get.
What a real composition looks like, step by step:
1. You give Claude a brief in plain language. "Welcome email for new signups, lead with the value prop, end with our standard footer." That's it. No structured input format, no schema.
2. Claude reads the design-system doc and the synced module list, picks an ordered sequence of modules — one header, body modules in between, one footer at the end — and calls orbit_compose_stripo_email.
3. The tool validates the structure. Exactly one header, exactly one footer, header at the top, footer at the bottom. If Claude is about to assemble something with two headers, the tool rejects it with an actionable error code (exactly_one_header, footer_must_be_last) that Claude can self-correct from inside the same conversation.
4. The tool stitches the modules into a full HTML email. Doctype declaration, head, deduped CSS (one shared stylesheet rather than N copies), body, modules each wrapped in their own table row, every esd-custom-block-id attribute preserved so the result round-trips into Stripo's editor cleanly when it lands.
5. The assembled HTML renders in chat as a visual artifact. You see the actual email — the way it'll look in the inbox — not a description, not a thumbnail. If something's off, you say so in chat ("swap the social footer for the standard one", "tighten the headline"), Claude re-composes, the artifact re-renders. Once it looks right, you tell Claude to push it, the tool re-calls with push: true, and the email lands in your Stripo workspace via the master template's generation area.
The whole loop is conversational. Module swaps, copy overrides, image changes — they all happen in chat, the preview re-renders before any push touches your Stripo workspace, and you control the moment the result actually crosses into Stripo.
Where the native integration beats the paste flow
Three real wins worth naming.
No drift between Stripo and Orbit. Modules change in Stripo? Re-run orbit_sync_stripo_modules and Orbit's catalog updates. Modules deleted in Stripo are tagged stripo_archivedlocally rather than hard-deleted, so a delete in Stripo doesn't silently remove a module Orbit was about to use. The local cache regenerates from Stripo on every sync — no version-skew problem to manage.
Tighter design adherence than the paste flow. Because Claude reads the design-system brief before composing, the emails Orbit produces use modules you've already approved in Stripo. Composition is constrained by your modular system, not by what the model thinks an on-brand email should look like. Sounds small. Compounds fast — every email starts on-brand by construction rather than by review.
Editable handoff, not a code dump. When the compose tool pushes via push: true, the result lands in your Stripo workspace as a real email — not a screenshot, not a wall of HTML in a chat window. Your designer opens it in Stripo's editor, tweaks whatever needs tweaking, and sends it through your existing ESP integration. Orbit composes; Stripo edits; whoever sends, sends. The boundaries between tools stay clean.
One constraint worth keeping in view: the integration only sees modules you've saved. Stripo's pre-built and public template gallery isn't exposed via the API. Everything Orbit pulls in is from your own library. If you have zero saved modules, sync returns zero modules — the fix is to save 2–3 in Stripo's editor (right-click any block → Save as module) and re-run the sync. Orbit doesn't generate modules from scratch; it composes from what you've already decided is on-brand.
Getting started, end to end
The canonical sequence, in the order to do it:
1. Run orbit_setup_stripo in Claude Desktop with Orbit installed. It tells you exactly which credentials are missing, walks you through getting them, and prompts you through the master-template creation. Lean on it — it's built to make setup frustration-free.
2. Run orbit_sync_stripo_modules. If it returns zero modules, that's the signal to go save 2–3 in Stripo's editor first (right-click any block → Save as module) before continuing.
3. Run orbit_document_stripo_design_system and read the output. It's the document Claude consumes before every compose call, and reading it is a useful audit of your own module library — you'll spot duplicates, naming gaps, and missing Liquid variables you didn't know about.
4. Ask Claude to compose an email. Plain language is fine. "Build me a welcome email using my Stripo modules" is enough. The artifact preview renders inline, you approve in conversation, and a final re-call with push: true sends the email to your Stripo workspace as an editable artifact.
The compose-loop UX is conversational from end to end. Edit the brief, swap modules, override copy, change the subject, re-render — all in chat, all before anything touches Stripo. The push step is always explicit: the integration never writes to your workspace without your confirmation.
For the protocol view of when Orbit applies this skill (and how it recovers from common failure modes — missing REST token, plan-tier gating, zero modules), see the Stripo Integration skill page. For the older paste-driven flow when this is overkill, the deliverability guide covers the plumbing that makes either path actually reach an inbox.
Read to the end
Scroll to the bottom of the guide — we'll tick it on your reading path automatically.
This guide is backed by an Orbit skill
Related guides
Browse allBraze naming conventions that survive a Friday afternoon
Every Braze workspace eventually becomes an archaeological dig. The convention that actually holds is four dimensions, six seconds to apply, and enforced by tooling rather than a Notion page nobody reads.
Liquid for lifecycle marketers — the complete Braze reference
Every personalised field in every Braze message runs through Liquid. Get it right and personalisation quietly improves every send. Get it wrong and 50,000 people see 'Hi {{${first_name}}}'. This reference covers the syntax and the production habits that stop that happening.
Personalisation that doesn't feel creepy
There's a line between personalisation that earns trust and personalisation that breaks it. It's not where most people think it is — it's about how you signal what you know, not what you know. Here's the line, how programs cross it without noticing, and the patterns that keep you on the right side.
The SMS playbook from the operator's seat
SMS is the highest-engagement and highest-risk channel in the lifecycle stack. Here's the compliance architecture, the copy discipline, and the frequency rules that keep SMS from destroying the goodwill it's uniquely positioned to create.
Subject line anatomy: the four parts every line that performs shares
Most subject-line advice is decoration tips — emoji, length, numbers. The lines that actually get opened share a structural pattern. Four parts in a specific order, the three distortions that ruin it, and the four rules that keep A/B tests honest.
Push notification copy that actually gets tapped
Push is the highest-interrupt channel in the stack. A bad push burns goodwill in under a second; a good one feels like a useful nudge from a friend. This is the copy discipline — specific words, specific structures, specific anti-patterns that reliably get a user to turn your notifications off for good.
Found this useful? Share it with your team.
Use this in Claude
Run this methodology inside your Claude sessions.
Orbit turns every guide on this site into an executable Claude skill — 63 lifecycle methodologies, 91 MCP tools, native Braze integration. Free for everyone.