Best Practices
Patterns for running embedded connectors in production — starting with the question most integrators hit first: what do you wire a freshly connected connector to by default?
You have the full Monad platform
The API key your backend holds is a full Monad API key — the same key you'd use to drive Monad directly. Embedding only changes where the connector form renders (inside a Monad-hosted iframe, so secrets never touch your JavaScript); it does not restrict what your backend can build.
That means the pipelines you stand up for your customers aren't limited to a simple input-to-output hop. Anything Monad offers is available to you:
- Transforms — reshape, rename, filter, and normalize records before they land.
- Enrichments — add context (geo-IP, threat intel, lookups) mid-pipeline.
- Multi-node routing — fan out to several destinations, branch on conditions, and chain transforms and enrichments in whatever order your product needs.
- Alerts and everything else in the platform — the embedded connector is just one node in a pipeline you fully control.
The embed SDK ships helpers for the common shapes (buildDevNullPipeline and the
lifecycle helpers), but those are conveniences, not limits. When you want more, build the
pipeline directly with POST /v2/{org}/pipelines/ (see
Connector Lifecycle) and include as many
transform, enrichment, and output nodes as you like. Your ability to use Monad on your
customers' behalf is exactly the same as using Monad directly.
Default ingress destinations
When a user connects a source (ingress), you decide where its data lands. The user never sees any of this; they see "connected." Choose the default that matches your stage:
Start with dev/null
For demos, and for a "connected but not yet routed" state, wire the new input to a throwaway sink with the shipped helper — zero setup, and the connector immediately shows as Active:
Code
This is the recommended default while you're getting an integration working. Nothing is
shared, so it also has the simplest teardown (CLEANUP_FULL).
Graduate to a real destination
When you're ready to actually keep the data, build the pipeline to a real output with the
raw POST /v2/{org}/pipelines/ primitive (see
Connector Lifecycle). Common shapes:
- A per-tenant store — each team's own destination (their S3, Snowflake, and so on).
- A global store that every tenant feeds.
- A richer pipeline — transforms or filters between the input and the output.
Match the cleanup policy to the shape:
CLEANUP_FULL for a throwaway sink, CLEANUP_KEEP_OUTPUT for a shared store other inputs
still feed.
Default egress source
When a user connects a destination (egress), fix the input side: provision one source per team, once, and let every destination the tenant adds fan out from it. The source is your product's own connector or a simple HTTP input.
Because that source feeds every tenant destination, never delete it. Egress teardown uses
a custom cleanup that keeps the source (input: false) and removes only the pipeline and
the user's output.
Naming defaults
Connector names are unique within a team, so two connectors of the same type would collide. Two levers:
- Omit
nameand Monad appends a short unique suffix for you. - Seed a unique name to allow two of the same type, e.g.
`${type.name} (${crypto.randomUUID().slice(0, 4)})`.
Set isNameEditable / isDescriptionEditable if you want the user to name it inside the
iframe (both default off). See the
options reference.
Keep the synthetic-data toggle off in production
createConnectorFrame exposes a synthetic option that surfaces Monad's internal
synthetic-data toggle. It defaults to false — leave it off in production; it's for
testing only.
Catalog performance
- Keep a server-side allow-list of the
type_ids you support. There are 300+ connector types; you rarely surface all of them. - Cache the connector-type catalog. Types are global and change rarely.
- Refresh a tenant's configured connectors only after a mutation (connect or delete), not on every render.
- Enrich status server-side. Listing configured connectors with their state does one
findIntegrationPipelinecall each. A handful is fine from the browser, but at scale fold it into your/api/connectorsroute so the browser gets one ready list.
Session and theming performance
- Reuse session tokens across mounts rather than minting one per iframe (see Authentication).
- Remember the remount cost.
appearanceapplies once at mount, so live re-theming meansdestroy()and remount. Debounce rapid changes if you build a theme customizer.
Deployment
- One API key, one team per customer, mapping on your server. Nothing new happens at deploy time except volume — provision a team as each customer onboards and keep the tenant-to-team record with your account data.
- Serve over HTTPS in production.
- Use the production endpoints by default:
apiBaseishttps://app.monad.com/apiandframeOriginishttps://app.monad.com/embed. Override them only for non-prod testing. - A
403on session mint in production is usually a stale or mis-signed API key — re-issue it. - A common local-dev snag:
POST /v3/sessionscan403when a WAF blocks theparentOrigin=http://localhost…parameter. PointframeOriginat a local UI dev server, or tunnel your host over HTTPS.
Next
- API Reference — full options, theming tokens, catalog reads, connector icons, and the backend route contract.
Support
For additional support contact support@monad.com