Overview

Spreeflo Forms let you build beautiful, conversational forms and surveys — then collect responses on a standalone Spreeflo page or embedded anywhere on your own website. You can ask any of a wide range of question types, map answers straight onto contacts in your audience, and show forms inline or as a popup, slider, popover, or side tab.

Forms are part of the free plan and include unlimited responses — there's no cap on how many people can submit. Every submission is saved in the form's Results tab, where you can review responses individually and download them all as a CSV for use in a spreadsheet or another tool. This guide covers the question types you can use, how to branch the flow with logic, how to map responses to contacts, every way to embed and trigger a form, how to push submissions to your own webhook, and the optional add-on to remove Spreeflo branding.

Question types

Add questions to your form from the Add content panel on the Content tab. Questions are grouped into categories so you can quickly find the right field. Most questions support a Required toggle, an optional description and image, and field-level settings (such as choice layout, character limits, or rating icons).

CategoryQuestion typeWhat the respondent does
Contact infoContact InfoEnters first name, last name, email, phone, and company in one step (each field can be shown, hidden, or required).
EmailEnters a single email address.
PhoneEnters a phone number with a country-code selector.
AddressEnters a full postal address (street, city, state, zip, country).
CompanyEnters a company name.
WebsiteEnters a website URL.
ChoiceMultiple ChoicePicks one or several options; supports an "Other" field, randomized order, and a selection limit.
DropdownSelects one option from a dropdown list.
Picture ChoiceSelects one or several image options.
Yes / NoPicks a binary answer with customizable labels.
LegalAccepts or declines a consent / agreement statement.
CheckboxTicks a single checkbox (e.g. opt-in confirmation).
Rating & rankingOpinion ScaleRates on a numeric scale with labels for the low, middle, and high ends.
RatingRates using star, heart, thumb, or smiley icons.
RankingDrags options into a preferred order.
MatrixAnswers several rows against shared columns in a grid.
Text, number & dateShort TextTypes a single line of text.
Long TextTypes a longer, multi-line response.
NumberEnters a number, with optional min/max limits.
DatePicks a date in your chosen format.
OtherVideo & AudioRecords a video or audio reply.
File UploadUploads one or more files.
Custom DesignDisplays a free-form designed block instead of a question.
Flow & structureWelcome ScreenOpens the form with an intro splash (one per form).
StatementShows a text-only screen with no input.
Question GroupGroups related questions under a shared heading.
Multi-Question PageShows several questions together on one page.
End ScreenCloses the form with a thank-you screen, optional share buttons, and a button.
Redirect to URLSends the respondent to an external URL after submitting.

Add logic to your form

By default a form runs straight down: question 1, question 2, question 3, ending. Logic lets an answer decide what comes next — skip questions that don't apply, send unqualified respondents to a different ending, or route each option to its own follow-up. You build it on the Workflow tab of the form builder, next to Content.

The logic map

The Workflow tab shows your whole form as a map. Each card is one screen, laid out left to right in flow order — welcome screen first, ending screens last. Questions nested inside a Question Group or a Multi-Question Page aren't separate cards; the container is the screen, so that's what the flow jumps to. Arrows show where the flow can go, and their style tells you why:

ArrowWhat it means
Blue, with a numberA conditional rule. The number matches the rule's number in the panel, so you can tell which rule draws which arrow.
Solid greyThe card's "in all other cases" jump — where the flow goes when no rule matches.
Light greyThe implicit next screen. Nothing is configured here — the form simply continues in order.
  • Click a card to open its rules in the panel on the right.
  • Drag from a card's output port (the connector on its right edge) onto another card to set that card's "in all other cases" jump — a quick way to wire the skeleton before adding conditions.
  • Drag cards to arrange them. Layout is saved with the form, and Re-layout in the toolbar puts everything back on the automatic grid.
  • Pan by dragging with the right or middle mouse button, zoom with the scroll wheel, or use the toolbar's zoom and fit to view buttons. Your view is remembered per form.
  • Undo / redo card moves and re-layouts from the toolbar, or with Ctrl/⌘ + Z and Ctrl/⌘ + Shift + Z.
  • Build a rule

    Select a card and use Add rule in the panel. A rule is one or more conditions plus a destination — read it as "if this, go there". Add several conditions with Add condition and choose whether they join with and (all must be true) or or (any one is enough).

    Below the rules sits In all other cases, go to — the fallback when no rule matches. Leave it on Next question (in order) to just continue down the form. On screens that can't have conditions (statements, media, groups) this is the only control, and it reads Always go to.

    Which conditions you can pick depends on the question's type — Spreeflo only offers comparisons that make sense for the answer:

    Question typeAvailable conditions
    Multiple Choice, Dropdown, Picture Choiceis, is not — compared against the question's own options.
    Yes / No, Legal, Checkboxis — pick the yes/no (or checked/unchecked) side, using your own labels.
    Number, Rating, Opinion Scaleis equal to, is not equal to, is greater than, is less than, is greater than or equal to, is less than or equal to.
    Short Text, Long Text, Email, Phone, Website, Companyis, is not, contains, does not contain, starts with, ends with.
    Dateis on, is before, is after.
    All of the aboveis answered, is not answered — useful for routing around skipped optional questions.
    Statements, media, groups, other screensNo conditions — there's no answer to test, so only the "always go to" jump applies.

    How the flow is decided

    When a respondent finishes a screen, Spreeflo works through that screen's rules in order and takes the first one that matches. If none match, it uses the "in all other cases" jump; if that isn't set, it moves to the next screen in order. Rule order is therefore meaningful — put your most specific rule first and reorder with the up/down arrows on each rule.

  • A condition on an unanswered question is never true — except is not answered, which is exactly how you catch skipped optional questions.
  • Text comparisons ignore case and surrounding spaces, so "Yes" matches "yes ".
  • Number comparisons compare numerically, and date comparisons compare whole days, not times.
  • On a question where several options can be selected, is matches when any selected option is the one you picked, and is not matches only when none of the selected options is.
  • If a rule points at a question you later deleted, the flow falls through to the next screen rather than breaking — and the builder shows you a warning.
  • Warnings on the map

    As you edit, Spreeflo checks the logic against the current form and flags problems on the affected card and in its panel. You'll see a warning when a rule has no conditions, when a jump points at a question that no longer exists, points back at the same question, or points at a welcome screen, when a condition no longer fits the question's type (for example after changing a question type), and when no path leads to a card — the sign of an orphaned question a respondent can never reach.

    Two screens don't take logic. A welcome screen always continues to the first question, and ending screens finish the form — nothing leaves them. To end a form early, point a rule at the ending screen you want: that's how a "not a fit right now" path or a qualification flow is built.

    Map responses to contacts

    A form can do more than collect answers — it can feed straight into your audience. Each form has a Map to contacts toggle. When it's on, every submission creates or updates a contact in your contact list, so responses don't just sit in a results table — they become people you can segment, message, and automate against.

    To make sure every submission lands on the right person, add a required Email field. Spreeflo uses the email address to match a submission to an existing contact or create a new one. If a form has no email field, only visitors already identified by the Spreeflo SDK (see Web Tracking & Analytics) are mapped — everyone else is recorded as an anonymous response.

    Mapping fields to attributes

    Beyond the built-in contact fields (email, name, phone, company, website), you can map almost any question to a contact attribute. Open a question's settings and use Map to attribute to choose which contact field the answer should be written to. For example, a "What's your role?" dropdown can be mapped to a job_title attribute, or a number question to a budget attribute.

    Contact options

    When Map to contacts is enabled, a few extra options become available:

  • Save as marketing contact — count mapped contacts as marketing contacts so they can receive campaigns (paid plans).
  • Update existing contacts — let new submissions overwrite attributes on a contact who has submitted before. Note that a contact's email address can't be changed once it's set — later submissions update other attributes but never overwrite the existing email.
  • Double opt-in — require the respondent to confirm by email before they're marked as subscribed (paid plans).
  • What this unlocks

    Mapping responses to contacts turns a form into a growth tool rather than a one-off survey. Common use cases include:

  • Lead capture — a "Contact sales" or "Request a demo" form that drops every lead straight into your audience.
  • Newsletter & waitlist signups — collect emails and instantly add subscribers, ready to receive their first campaign.
  • Enrich contact profiles — ask preferences or qualifying questions and store the answers as attributes for personalization.
  • Segmentation & automation — because answers land on the contact, you can build segments from them and trigger journeys the moment a form is submitted.
  • Tip: Leave Map to contacts off when you only want anonymous feedback (e.g. an NPS survey) and don't need the responses tied to people in your audience.

    Embed your form

    Every form is reachable at its own Spreeflo-hosted link, so you can share it directly without any setup. To put a form on your own website, you have two options — embed it inline in the page, or show it as a popup. The difference matters because they're installed differently: inline embeds use a small embed.js snippet, while popups require the full Spreeflo SDK.

    Embed a form inline

    An inline embed renders the form directly inside your page, in the spot where you place the code. There are two inline styles:

    TypeHow it appears
    StandardThe form renders inside your page at a width and height you set (with optional responsive auto-height).
    Full PageThe form fills the entire browser viewport, like a dedicated landing page.

    From the Embed tab, Spreeflo gives you a small snippet to copy. Paste it into your page wherever you want the form to appear:

    <div data-spreeflo-embed="YOUR_EMBED_ID"></div>
    <script src="https://spreeflo.com/cdn/sdk/embed.js"></script>
  • The <div data-spreeflo-embed="…"> marks where the form renders and identifies which form to load.
  • embed.js is Spreeflo's lightweight loader script. It scans the page for your embed placeholder and renders the form. You only need to include it once per page, even if you embed several forms — no SDK or account key required.
  • The Embed tab also includes step-by-step instructions for popular platforms like WordPress, Shopify, and Squarespace, in case you'd rather paste the snippet through their editors.

    A popup overlays the form on top of your page and opens based on visitor behavior, rather than sitting inline. Popups come in four styles:

    TypeHow it appears
    PopupA modal that opens over your page with a dimmed backdrop.
    SliderA panel that slides in from the edge of the screen.
    PopoverA floating chat-style panel attached to a launcher button.
    SidetabA fixed tab pinned to the side of the screen that opens a panel when clicked.
    Popups require the Spreeflo SDK. Unlike inline embeds, popups aren't loaded by the embed.js snippet — they're delivered through the full Spreeflo SDK installed on your site. When you create a popup, Spreeflo shows you the SDK install steps instead of an embed snippet. See Web Tracking & Analytics for how to install the SDK. Once it's on your site, your popups appear automatically — no per-form code to paste.

    Each popup style can be styled in the builder — size, launcher button text and color, launcher position (left or right), border radius, and overlay opacity. Choose a trigger for when it opens:

  • On button click — opens only when the visitor clicks the launcher button (the default).
  • On page load — opens as soon as the page is ready.
  • After a delay — opens after a set number of seconds.
  • On scroll — opens once the visitor scrolls past a percentage of the page.
  • On exit intent — opens when the visitor's mouse moves to leave the page.
  • You can also fine-tune close behavior — keep the form open until it's submitted, auto-close after submission, or prevent it from reopening once a visitor has dismissed it — so popups stay helpful rather than annoying.

    Forms and the Spreeflo SDK

    To recap the two paths: inline embeds need only the embed.js snippet and nothing else, while popups need the full Spreeflo SDK installed on your site. The SDK is the same one used for web analytics and visitor tracking, so if you already have it installed, popups work right away.

    With the SDK in place, forms also integrate more deeply: a submission is tied to the SDK's identified visitor, so even forms without an email field can be mapped to the right contact, form submissions become events you can act on, and Spreeflo can deliver scheduled popup forms as part of your campaigns without you editing the page again. For how to install the SDK, identify visitors, and track events, see Web Tracking & Analytics.

    Attach your own metadata

    Sometimes the answers alone aren't enough — you need to know where a submission came from. Which account was the visitor logged into? Which pricing page did they fill the form on? Which A/B variant did they see? Add a data-spreeflo-metadata attribute to the embed placeholder with a JSON object, and those keys travel with the submission:

    <div
      data-spreeflo-embed="YOUR_EMBED_ID"
      data-spreeflo-metadata='{"plan":"trial","accountId":"acct_7712"}'
    ></div>

    The metadata is stored on the response and included in the metadata field of the webhook payload, so your server sees exactly the context your page had. Since the attribute is rendered by your own page, you can fill it in with template values — a user id from your backend, a plan name, a campaign code.

  • The value must be a JSON object ({ }, not an array or a bare value). Invalid JSON is ignored — the form still loads and submits, just without your metadata, and a warning is logged to the browser console.
  • Use single quotes around the attribute so the JSON's double quotes don't need escaping, as in the example above.
  • Spreeflo adds userAgent and referrer to every submission's metadata. These are reserved — if your object uses the same keys, Spreeflo's values win.
  • Sharing a form through its Spreeflo-hosted link instead of an embed? Append ?spMeta= followed by the URL-encoded JSON object to the link, and it behaves the same way.
  • Don't put secrets in metadata. It lives in your page's HTML and in the form URL, so a visitor can read it and change it. Treat it as a hint about context, and re-verify anything security-sensitive server-side when the webhook arrives.

    Listen to form events

    When a form is embedded on your site, it tells the host page what the visitor is doing — so you can react to it. Use this to redirect after a submission, fire your own analytics or conversion tracking, reveal a thank-you message, or anything else. The same events fire for both inline embeds (embed.js) and popups (the Spreeflo SDK), with the same data, so you write your handler once.

    EventFires when
    openThe form becomes visible — an overlay opens, or an inline form mounts on the page.
    submitThe visitor submits the form. Fires exactly once per submission.
    dismissThe visitor closes the form without submitting — a genuine dismissal.
    closeThe form closes for any reason. Check detail.submitted to tell whether a submit came first.

    You can listen in either of two equivalent ways — pick whichever fits your site. The simplest is to assign a callback object to window.SpreefloEmbed; each handler runs when its event fires:

    window.SpreefloEmbed = {
      onOpen:    (detail) => { /* form became visible */ },
      onSubmit:  (detail) => { /* submitted — detail.embedId, detail.formId */ },
      onDismiss: (detail) => { /* closed WITHOUT submitting */ },
      onClose:   (detail) => { /* closed for any reason — detail.submitted says which */ },
    };

    Or listen for DOM events named spreeflo:<event>. For inline embeds these are dispatched on the embed's placeholder and bubble up, so a single window listener catches every form on the page:

    window.addEventListener('spreeflo:submit', (e) => {
      console.log('Form submitted', e.detail.embedId, e.detail.formId);
    });
    
    window.addEventListener('spreeflo:dismiss', (e) => {
      // visitor closed the form without submitting
    });

    Every event carries a detail object with the same shape — the type of event, the embedId (the data-spreeflo-embed value, or the popup's embed id), the published formId, and, on close, a submitted boolean. Use embedId or formId to react only to a specific form when you embed more than one.

  • Inline forms only fire open and submit — they have no close button, so they never emit dismiss or close.
  • Every dismissal is also a close (with submitted: false), but a close that follows a submit fires only close with submitted: true — never dismiss.
  • If a popup is set so visitors can't close it until they submit, no dismiss will ever fire for it.
  • Send responses to a webhook

    Form events tell your page what happened. A webhook tells your server. Turn one on and Spreeflo sends every submission to an endpoint you control as a POST request with a JSON body — so responses can flow straight into your CRM, database, Slack channel, or any internal tool, without polling the Results tab or exporting a CSV.

    Open your form's Settings (the cog in the builder toolbar), go to the Integrations tab, and switch on Send responses to a webhook. Then paste your endpoint URL. Webhooks are available on every plan, including free.

  • The endpoint must be a publicly reachable https URL — plain http isn't accepted, because submissions can carry personal data.
  • Your endpoint should reply with any 2xx status to acknowledge delivery.
  • Webhooks fire in addition to everything else — responses are still saved to Results, and contact mapping still runs as normal.
  • What Spreeflo sends

    Each submission is delivered as a single JSON POST with Content-Type: application/json:

    {
      "formId": "frm_8Kq2wZ",
      "formVersion": 7,
      "responseId": "res_3xN9dLpQ",
      "submittedAt": "2026-07-23T09:41:12.804Z",
      "contactId": "con_51bTmA",
      "email": "ada@example.com",
      "answers": {
        "q_email": {
          "type": "email",
          "title": "What's your work email?",
          "value": "ada@example.com"
        },
        "q_team_size": {
          "type": "dropdown",
          "title": "How big is your team?",
          "value": "11-50"
        },
        "q_notes": {
          "type": "long_text",
          "title": "Anything else we should know?",
          "value": "We're migrating off a competitor next quarter."
        }
      },
      "metadata": {
        "plan": "trial",
        "accountId": "acct_7712",
        "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) …",
        "referrer": "https://yoursite.com/pricing"
      }
    }
    FieldWhat it contains
    formIdThe form the submission belongs to.
    formVersionThe published version of the form that was filled in.
    responseIdUnique id for this submission. Use it to de-duplicate — a retry re-sends the same responseId.
    submittedAtWhen the form was submitted, as an ISO 8601 timestamp.
    contactIdThe contact this submission was mapped to, when the visitor could be identified — otherwise null.
    emailThe identified visitor's email address — otherwise null.
    answersOne entry per question, keyed by question id, with the question's type, title, and the answer given.
    metadata Context captured with the submission — the userAgent and referrer Spreeflo records, plus any keys you attached yourself with data-spreeflo-metadata.

    Identified visitors

    contactId and email are what turn a webhook payload into something actionable — they let your system attach the submission to a person you already know instead of an anonymous row. A visitor counts as identified when either:

  • they answered an email field in the form, so Spreeflo can match or create a contact from that address; or
  • the Spreeflo SDK already recognised them on your site — for example they were identified after logging in, or they'd submitted a form earlier from the same browser (see Web Tracking & Analytics).
  • For anonymous submissions — no email field answered and no SDK identity — both fields are null and the rest of the payload is delivered as usual. The single best way to get identified submissions is to add a required Email field to your form.

    Verify the signature

    Your endpoint is a public URL, so anyone who finds it could post fake submissions to it. To prevent that, set an optional signing secret in the same Integrations tab. When one is set, every request carries an X-Spreeflo-Signature header containing an HMAC-SHA256 of the raw request body, computed with your secret. Recompute it on your side and compare — if it doesn't match, reject the request.

    import crypto from 'node:crypto';
    
    // Express — note express.raw(), so we hash the exact bytes Spreeflo sent
    app.post('/hooks/spreeflo', express.raw({ type: 'application/json' }), (req, res) => {
      const signature = req.get('X-Spreeflo-Signature') || '';
      const expected = crypto
        .createHmac('sha256', process.env.SPREEFLO_WEBHOOK_SECRET)
        .update(req.body) // the raw Buffer, not a parsed object
        .digest('hex');
    
      const valid =
        signature.length === expected.length &&
        crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected));
    
      if (!valid) return res.sendStatus(401);
    
      const submission = JSON.parse(req.body.toString('utf8'));
      // ignore submissions you've already handled — retries reuse responseId
      handleSubmission(submission);
    
      res.sendStatus(200); // acknowledge quickly; do slow work in the background
    });
    Sign against the raw body. Compute the HMAC over the exact bytes you received, before any JSON parsing or re-serializing — re-encoding the payload changes the signature. And compare with a timing-safe function, as above, rather than ===.

    Delivery & retries

  • Submissions wait for your endpoint. Form submissions wait for up to 3 seconds for your endpoint to acknowledge delivery before returning to the form to emit spreeflo:submit event for embedded and popup forms.
  • Failures are retried. If your endpoint times out, refuses the connection, or returns a non-2xx status, Spreeflo retries a few times with increasing delays before giving up. If failures continue for 3 days, the form webhook will be disabled and the form will no longer send submissions to your endpoint.
  • Retries mean a payload can arrive twice. If your endpoint replied slowly or the acknowledgement was lost, you may see the same submission again — treat responseId as an idempotency key and ignore ones you've already processed.
  • Changing the URL or secret takes effect after publishing for new submissions; it doesn't replay past ones. Your endpoint is called with the settings saved at the time of publishing.
  • Webhook or form events? Use form events for anything in the browser — redirects, thank-you messages, conversion pixels. Use a webhook for anything that must be reliable and server-side — creating a CRM record, notifying your team, kicking off fulfilment. Browser events can be missed if the visitor closes the tab; webhooks are sent from Spreeflo's servers and retried.

    Remove Spreeflo branding

    By default, forms show a small "Powered by Spreeflo" badge in the footer. To hide it, subscribe to the No Spreeflo Branding add-on for $10 per month. It:

  • Removes the "Powered by Spreeflo" badge from every form.
  • Applies across your entire account, not just one form.
  • Can be cancelled anytime.
  • Toggle Spreeflo branding off in your form's settings to start. If you're not subscribed yet, you'll be prompted to add the subscription first.

    Pricing & limits

    Forms are included on the free plan with unlimited responses — there's no limit on how many submissions you can collect, on any plan. The form builder, question types, embed types, contact mapping, and webhooks are all available for free. Some contact options, like marking submissions as marketing contacts and double opt-in, are part of paid plans.

    For a full breakdown of what each plan includes, see About Spreeflo Pricing Plans.

    Need Immediate Help? Contact our support team at support@spreeflo.com or check our other guides for more information.