Embedding forms
One snippet turns any static page into structured intake: your marketing site, a client's WordPress blog, a Notion-published page, the plain HTML brochure site an agency shipped in 2019. Visitors see a form; you see records flowing onto a board, triggering webhooks, ready for your team or an AI agent — with zero backend on the embedding site.
How it works
Each form in Snapi has a public submission endpoint:
POST https://api.snapi.ca/api/v1/public/submit/:entityId
The embed script renders your form automatically from its field schema and posts to this endpoint. Records appear in your workspace in real time.
Getting the embed snippet
- Open your workspace and navigate to Forms.
- Click the form you want to embed.
- Click the Share / Embed button in the top-right toolbar.
- Copy the snippet from the Embed tab.
The snippet looks like this:
<script
src="https://app.snapi.ca/embed.js"
data-entity="ent_abc123xyz"
data-theme="light"
defer>
</script>
<div id="snapi-form"></div>
Attributes
| Attribute | Required | Description |
|---|---|---|
data-entity |
Yes | Your form ID (starts with ent_) |
data-theme |
No | light (default) or dark |
data-redirect |
No | URL to redirect the visitor after a successful submission |
data-success-msg |
No | Custom text shown after submission (default: "Thank you!") |
iframe embed
If you prefer an iframe over a script tag (e.g. for stricter CSP policies), copy the snippet from your form's Public Form tab. The URL includes your organization and form slugs:
<iframe
src="https://app.snapi.ca/embed/your-org/contact-form"
width="100%"
height="600"
frameborder="0"
style="border:none;border-radius:8px;">
</iframe>
Restricting where your form can be used
Set Allowed Domains in the form's Public Form tab (e.g. example.com, another.com) to control where the form works. Enforcement happens in two places:
- When the embed page loads — an iframe on a site that isn't on your list gets "This form cannot be embedded on this site" instead of the form.
- When a submission arrives — script-embed submissions from a non-allowed origin are rejected with
403.
Subdomains are included automatically (example.com also allows www.example.com). Leave the field empty to allow embedding anywhere.
Gotchas
- "app.snapi.ca refused to connect" — the form isn't public (enable the Public Form toggle and save), or the iframe URL wasn't copied from the Embed Code box.
- Don't add
app.snapi.cato your Allowed Domains. Submissions from an iframe embed technically arrive from Snapi's own origin — that's normal browser behavior and handled automatically. Your list should contain only the site(s) that embed the form. - Domain restriction is a strong deterrent, not DRM. Browsers verify the embedding site via standard headers, which a non-browser client can spoof. For sensitive flows, enable Require Authentication or validate submissions in a pre-submit webhook.
- Internal fields never appear on public forms — fields marked Internal are stripped from the public form config and from any submission that tries to set them.
- Script updates:
snapi.jsis cached for up to an hour — changes to the SDK can take that long to reach embedded pages.
Styling the embedded form
The embed script injects a shadow DOM component, so your page's CSS won't interfere with it. You can control appearance using the data-theme attribute or the following CSS custom properties placed on the host #snapi-form element:
#snapi-form {
--snapi-accent: #2551ed;
--snapi-radius: 8px;
--snapi-font: 'Inter', sans-serif;
}
Submission quotas
Public form submissions count toward your plan's monthly submission quota. When the quota is reached, the embed shows a "form temporarily unavailable" message to visitors.
| Plan | Submissions / month |
|---|---|
| Free | 500 |
| Starter | 5,000 |
| Team | 25,000 |
Quotas reset on the first of each month. See Plans & limits for the full comparison.
Spam and rate limiting
The public submit endpoint is IP-rate-limited (60 requests per 15 minutes per IP) regardless of plan. For high-volume use cases, authenticated API access via an API key is recommended instead.
Receiving submissions in real time
Every submission triggers your form's configured webhooks (Starter and Team plans). You can use a post-submit webhook to send confirmation emails, sync to a CRM, or trigger automation in n8n.