Pollaris Docs
Embed a form

Custom one-page form

Submit a linear Pollaris form atomically from your own HTML.

One-page mode connects familiar HTML forms—contact, lead, registration, and feedback forms—to Pollaris. It submits every field in one atomic request.

Requirements

The published form must be strictly linear:

  • Each question flows unconditionally to the next question.
  • The final question ends the form.
  • There are no branches, backward edges, or quiz scoring rules.
  • Each question has a unique stable field key.
  • Enable atomic one-page submissions is turned on in Share → Embed.

If the form does not qualify, use the headless step-by-step SDK.

Stable field keys

Your HTML input names must match Pollaris question keys:

<input name="name">
<input name="email" type="email">
<textarea name="message"></textarea>

Keys match ^[a-z][a-z0-9_]{0,63}$ and are unique within the form. Changing a prompt or moving a question does not change its key. Changing a key is a breaking change for your website integration.

Submit your HTML form

<form id="contact-form">
  <label>
    Name
    <input name="name" autocomplete="name">
  </label>
  <label>
    Email
    <input name="email" type="email" autocomplete="email" required>
  </label>
  <label>
    Message
    <textarea name="message" required></textarea>
  </label>
  <button type="submit">Send</button>
  <p id="contact-status" role="status"></p>
</form>

<script type="module">
  import { createPollarisClient } from 'https://cdn.example.com/embed/v1/index.js';

  const client = createPollarisClient({
    form: 'FORM_SLUG',
    apiBase: 'https://api.example.com'
  });
  const form = document.querySelector('#contact-form');
  const status = document.querySelector('#contact-status');

  form.addEventListener('submit', async (event) => {
    event.preventDefault();
    const button = form.querySelector('button[type="submit"]');
    button.disabled = true;

    try {
      const values = Object.fromEntries(new FormData(form));
      await client.submit(values, {
        context: {
          utm_source: new URLSearchParams(location.search).get('utm_source') ?? undefined,
          language: navigator.language,
          screen_w: window.innerWidth
        }
      });
      form.reset();
      status.textContent = 'Your message was sent.';
    } catch (error) {
      status.textContent = error.code === 'VALIDATION_FAILED'
        ? error.message
        : 'Your message could not be sent. Please try again.';
    } finally {
      button.disabled = false;
    }
  });
</script>

Manifest and version changes

client.submit() first loads /v1/embed/FORM_SLUG/manifest, validates keys and values locally, and submits the manifest version. Pollaris rejects stale versions so answers are never silently applied to a changed schema. The SDK manages this flow for you.

Unknown fields are rejected. Missing optional values are normalized to null; missing required values fail validation. The server remains authoritative even if browser validation is bypassed.

Idempotency

The SDK generates an idempotency key for each submission. To safely retry an application-managed submission, generate a key once and reuse it only for the identical values:

const idempotencyKey = crypto.randomUUID();

await client.submit(values, { idempotencyKey });

Never reuse one key for a different submission. Pollaris rejects a reused key when the values differ.

Field-value notes

  • FormData produces strings. For rating, star, or NPS fields, convert the selected value to a number.
  • Multiple-choice fields expect an array, so collect repeated/checkbox values with formData.getAll(key).
  • A contact question expects an object containing its configured contact fields; separate text questions are often easier for a custom one-page form.
  • Client-side validation is for immediate feedback only; always handle server validation errors.

On this page