Form Testing Guide
How to Test Typeform Embed with Playwright: Complete 2026 Guide
A scenario-by-scenario walkthrough of testing Typeform embedded forms with Playwright. Full iframe isolation, logic jump branches, hidden fields, multi-step navigation, thank you screen redirects, and webhook response verification.
βTypeform has collected over 800 million responses across millions of forms, making it one of the most widely used conversational form platforms for lead capture, surveys, and product signups.β
Typeform
Typeform Embed Response Flow
1. Why Testing Typeform Embeds Is Harder Than It Looks
Typeform embeds your form inside a sandboxed iframe served from form.typeform.com. That single architectural decision cascades into six distinct testing challenges. First, the iframe is cross-origin, which means Playwright's default page context cannot reach any elements inside it. You must use frameLocator() to obtain a handle into the Typeform DOM, and every subsequent locator call must be scoped to that frame.
Second, Typeform forms are single-page applications inside that iframe. Each question is rendered one at a time with smooth CSS transitions. There are no URL changes between questions, no page navigations, and no network requests you can intercept to determine when the next question is ready. Your test must rely on DOM visibility checks rather than network or URL watchers.
Third, Typeform logic jumps can skip questions, loop back to earlier questions, or branch into entirely different paths based on previous answers. A form with 10 questions might have 12 or more distinct paths through it, and the DOM for skipped questions never renders at all. You cannot just fill every field sequentially; you must account for conditional routing at each step.
Fourth, hidden fields are injected via URL parameters on the embed URL, passed into the iframe, and included in the final response payload. They never appear in the visible DOM, so you cannot assert their values through standard locator checks. Fifth, the thank you screen can either show a Typeform default message, render a custom ending, or redirect the parent page to an external URL. Each behavior requires a different assertion strategy. Sixth, webhook payloads fire asynchronously after submission and contain the full response data including hidden fields, making them critical to verify but impossible to check from the browser alone.
Typeform Embed Architecture
Host Page
Your app with embed script
Embed SDK
Injects iframe element
Typeform Iframe
form.typeform.com
Question SPA
Single-page form engine
Typeform API
Stores responses
Webhook
POST to your endpoint
Logic Jump Decision Tree
Question 1
Company size
Evaluate Rule
If > 50 employees
Branch A
Enterprise questions
Branch B
SMB questions
Merge Point
Final question
A robust Typeform embed test suite addresses all six of these challenges. The sections below walk through each scenario with runnable Playwright TypeScript you can copy directly into your project.
2. Setting Up a Reliable Test Environment
Before writing any scenarios, you need a Typeform workspace with a form configured specifically for testing. Create a dedicated workspace (Typeform allows multiple workspaces on all paid plans) so your test forms stay isolated from production surveys. Build a test form with at least six questions covering text input, multiple choice, dropdown, number, email, and a rating question. Add two logic jumps: one that branches on a multiple choice answer and one that skips a question based on a number threshold. Configure three hidden fields: user_id, session_id, and utm_source. Set the thank you screen to redirect to a specific URL on your test domain. Finally, create a webhook endpoint that logs payloads so you can verify submission data.
Typeform Test Environment Checklist
- Create a dedicated Typeform workspace for testing
- Build a test form with 6+ question types (text, choice, dropdown, number, email, rating)
- Add two logic jump rules (branch on choice, skip on number threshold)
- Configure three hidden fields: user_id, session_id, utm_source
- Set thank you screen redirect to your test domain
- Create a webhook endpoint to capture submission payloads
- Note the form ID from the Typeform URL (e.g., abc123XY)
- Generate a Personal Access Token for the Typeform API
Environment Variables
Playwright Configuration for Iframe Testing
Typeform iframes load from form.typeform.com, a different origin than your application. Playwright's frameLocator() handles cross-origin iframes automatically, but you need generous timeouts because the Typeform embed SDK loads asynchronously and the iframe content can take several seconds to render, especially on CI runners with limited bandwidth.
Webhook Receiver Setup
To verify that Typeform fires the correct webhook payload after submission, run a lightweight Express server that captures and stores incoming payloads. Start this server before your test suite and query it from your tests to assert on the response data, including hidden field values.
3. Scenario: Accessing the Typeform Iframe
The first and most fundamental scenario is simply reaching into the Typeform iframe and interacting with any element. If you cannot reliably locate and interact with elements inside the embed, none of the subsequent scenarios will work. The Typeform embed SDK injects an iframe with a data-testid attribute of iframe (on the standard embed) or a title attribute containing the form name. The iframe's src points to form.typeform.com/to/FORM_ID. You use Playwright's frameLocator() to get a handle, and all subsequent queries run inside that frame context.
One common mistake is trying to use page.locator() to find elements inside the Typeform iframe. This will always fail because the elements live in a separate browsing context. Another mistake is querying the iframe before it has fully loaded; the Typeform SDK inserts the iframe asynchronously, and the iframe itself may take a few seconds to render the first question. Always wait for a known element inside the frame before proceeding.
Accessing the Typeform Iframe
StraightforwardGoal
Load a page containing an embedded Typeform, get a handle to the iframe, and confirm the first question is visible and interactive.
Preconditions
- App running at
APP_BASE_URLwith a page that embeds the Typeform - The Typeform embed uses the standard SDK (
@typeform/embed) - Form ID is configured in
TYPEFORM_FORM_ID
Playwright Implementation
What to Assert Beyond the UI
- The iframe
srcattribute contains your form ID - No console errors related to CORS or Content Security Policy appear
- The Typeform SDK script tag is present in the host page DOM
Iframe Access: Playwright vs Assrt
import { test, expect } from '@playwright/test';
test('access Typeform iframe', async ({ page }) => {
await page.goto('/contact');
const iframeSelector = 'iframe[data-testid="iframe"]';
await page.waitForSelector(iframeSelector, { timeout: 15_000 });
const typeform = page.frameLocator(iframeSelector);
const firstQuestion = typeform
.locator('[data-qa="question-container"]').first();
await expect(firstQuestion).toBeVisible({ timeout: 10_000 });
const inputField = typeform.locator('input[type="text"]').first();
await expect(inputField).toBeEnabled();
});4. Scenario: Multi-Step Form Navigation
Typeform presents one question at a time. After answering a question, the user either clicks an βOKβ button, presses Enter, or the form auto-advances (depending on question type and settings). Each transition involves a CSS animation that slides the current question out and the next question in. There is no URL change, no page navigation, and no new iframe load. From Playwright's perspective, you are clicking and waiting for DOM mutations inside the same frame context.
The tricky part is timing. If you type an answer and immediately try to click βOK,β the button may not be enabled yet because Typeform validates the input asynchronously. If you click βOKβ and immediately try to interact with the next question, the transition animation may still be running and the next input may not be interactive yet. The reliable approach is to wait for each question container to become visible and its primary input to become enabled before interacting.
Multi-Step Form Navigation
ModerateGoal
Fill out three consecutive questions (text, multiple choice, email) and verify each transition completes before interacting with the next question.
Playwright Implementation
What to Assert Beyond the UI
- The progress bar (if enabled) advances with each answered question
- Pressing the keyboard
Enterkey also advances the form, not just the OK button - The back button or keyboard shortcut navigates to the previous question without losing answers
Multi-Step Navigation: Playwright vs Assrt
import { test, expect } from '@playwright/test';
test('multi-step Typeform navigation', async ({ page }) => {
await page.goto('/contact');
const typeform = page.frameLocator('iframe[data-testid="iframe"]');
async function waitForQuestion(idx: number) {
const q = typeform.locator('[data-qa="question-container"]').nth(idx);
await expect(q).toBeVisible({ timeout: 10_000 });
return q;
}
await waitForQuestion(0);
await typeform.locator('input[type="text"]').first().fill('Jane Doe');
await typeform.getByRole('button', { name: /ok/i }).click();
await page.waitForTimeout(800);
await waitForQuestion(1);
await typeform.getByRole('button', { name: /51-200/i }).click();
await page.waitForTimeout(800);
await waitForQuestion(2);
await typeform.locator('input[type="email"]')
.fill(`test+${Date.now()}@example.com`);
await typeform.getByRole('button', { name: /ok/i }).click();
});5. Scenario: Logic Jump Branching
Logic jumps are Typeform's conditional routing feature. Based on the answer to one question, the form can skip ahead to a specific question, jump to a different branch of questions, or go directly to the thank you screen. This is the feature that makes Typeform forms powerful for segmentation, but it also makes them challenging to test because a single form can have many distinct paths through it.
The key testing strategy is to identify all logic jump rules in your form and test each branch explicitly. For a form with two logic jumps that each have two outcomes, you need four test cases to achieve full branch coverage. Each test case must provide the specific answer that triggers the target branch and then verify that the correct follow-up question appears (and that skipped questions do not appear).
You can review your form's logic jumps in the Typeform builder under the βLogicβ panel, or fetch them programmatically via the Typeform Create API. The API response includes a logic array on each field that defines the conditions and destination references. Use this to generate your test matrix.
Logic Jump: Enterprise Branch
ComplexGoal
Answer the company size question with β201+β to trigger the enterprise logic jump, and verify that the enterprise-specific follow-up questions appear while the SMB questions are skipped.
Playwright Implementation
Fetching Logic Rules via the Typeform API
To programmatically discover all branches in your form, query the Typeform Create API. The response includes the logic configuration for each field with conditions and jump destinations.
7. Scenario: Thank You Screen and Redirect
After the user submits their final answer, Typeform shows a thank you screen. This screen can behave in three distinct ways depending on your form configuration. The default behavior shows a Typeform-branded βThanks for completing this typeform!β message inside the iframe. A custom ending replaces that with your own message, image, and optional button. A redirect ending navigates the parent page (not just the iframe) to an external URL. Each of these requires a different assertion strategy.
The redirect ending is the most complex to test. When configured, Typeform uses window.top.location.href (or postMessage to the parent) to navigate the entire browser window away from your application to the target URL. In Playwright, this means the page context changes entirely. You must use page.waitForURL() on the main page (not the frame) to detect the redirect, and your assertion runs against the new page, not the original embed host.
Thank You Screen and Redirect
ModerateGoal
Complete a form and verify all three thank you screen variants: default Typeform ending, custom ending with message and button, and redirect to an external URL.
Playwright Implementation
Thank You Redirect: Playwright vs Assrt
test('thank you: redirect to external URL', async ({ page }) => {
await page.goto('/survey-redirect');
const typeform = page.frameLocator('iframe[data-testid="iframe"]');
// Fill all questions
const nameInput = typeform.locator('input[type="text"]').first();
await expect(nameInput).toBeVisible({ timeout: 10_000 });
await nameInput.fill('Redirect Tester');
await typeform.getByRole('button', { name: /ok/i }).click();
await page.waitForTimeout(800);
const choice = typeform.getByRole('button', { name: /1-50/i });
await choice.click();
await page.waitForTimeout(800);
const emailInput = typeform.locator('input[type="email"]');
await emailInput.fill(`test+${Date.now()}@example.com`);
await typeform.getByRole('button', { name: /ok/i }).click();
await page.waitForTimeout(800);
await typeform.getByRole('button', { name: /submit/i }).click();
await page.waitForURL('**/thank-you**', { timeout: 15_000 });
expect(page.url()).toContain('/thank-you');
});8. Scenario: Webhook Response Verification
Typeform webhooks fire after a response is submitted. The webhook payload contains the full response data: all answers, hidden field values, metadata (user agent, landed at, submitted at), and the form definition reference. For many applications, the webhook is where the real business logic begins: creating a CRM lead, sending a follow-up email, triggering an onboarding sequence, or updating a database record. Testing the webhook payload is therefore just as important as testing the form UI.
Typeform signs every webhook request with an HMAC SHA-256 signature in the Typeform-Signature header. Your webhook receiver should verify this signature to prevent spoofed payloads. In your test environment, the webhook receiver (from Section 2) captures and stores every incoming payload so your Playwright tests can query the most recent payload and assert on its structure and values.
Webhook Response Verification
ComplexGoal
Submit a Typeform response and verify the webhook payload contains the correct answers, hidden fields, signature, and metadata.
Playwright Implementation
Verifying Webhook Signature
9. Common Pitfalls That Break Typeform Test Suites
The following pitfalls come from real issues reported by developers testing Typeform embeds in production CI pipelines. Each one can cause intermittent test failures that are difficult to diagnose without understanding Typeform's internal behavior.
Pitfalls to Avoid
- Using page.locator() instead of frameLocator() for iframe elements. Every Typeform element lives inside a cross-origin iframe; page-level locators will never find them.
- Not waiting for the CSS transition between questions. Typeform uses 300-500ms slide animations. Interacting during the transition causes flaky clicks on stale elements.
- Assuming sequential question order when logic jumps are configured. The DOM only renders the current question; skipped questions never appear at all.
- Hardcoding question indices instead of using content-based selectors. Typeform reorders questions when you edit the form in the builder, breaking nth-child selectors.
- Ignoring the embed SDK loading delay. The Typeform SDK script is async; the iframe may not exist in the DOM for 2-5 seconds after page load on slow CI runners.
- Testing hidden fields by looking at the visible DOM. Hidden fields are never rendered; verify them via network interception or webhook payloads only.
- Forgetting that redirect endings navigate the parent window, not the iframe. Use page.waitForURL() on the main page context, not on the frame locator.
- Running tests in parallel against the same webhook endpoint without clearing payloads between runs. Stale payloads from previous tests cause false positives.
Iframe Selector Fragility
Typeform updates their embed SDK and internal DOM structure periodically. The data-testid="iframe" attribute has been stable across recent SDK versions, but the internal question container selectors like [data-qa="question-container"] can change between major Typeform releases. Pin your Typeform embed SDK version in package.json to avoid surprise breakages, and add a smoke test that asserts the existence of your critical selectors before running the full suite.
Webhook Delivery Latency
Typeform's webhook delivery is eventually consistent. In testing, payloads typically arrive within 1 to 3 seconds of submission, but during high-traffic periods, delivery can take up to 30 seconds. Your test should poll the webhook receiver with retries rather than using a fixed waitForTimeout. If the webhook never arrives within your timeout window, check the Typeform dashboard's webhook log for delivery failures, which commonly occur when the webhook endpoint is unreachable from Typeform's servers (a frequent issue in local development without a tunnel).
Content Security Policy Blocking the Embed
If your application has a strict Content Security Policy, the Typeform embed script and iframe may be blocked entirely. Your CSP must include frame-src form.typeform.com and script-src embed.typeform.com at minimum. Add a test that checks for CSP violation errors in the browser console. In Playwright, use page.on('console', ...) to capture and assert that no CSP errors appear when the embed loads.
10. Writing These Scenarios in Plain English with Assrt
Every scenario above requires careful iframe handling, precise timing around CSS transitions, and awareness of Typeform's internal DOM structure. The multi-step navigation scenario alone is over 40 lines of Playwright TypeScript. The webhook verification scenario adds network polling, signature verification, and payload structure assertions. Multiply all of that by the number of logic jump branches in your form and you have a substantial test maintenance burden.
Assrt eliminates the iframe boilerplate entirely. When you describe a scenario that involves a Typeform embed, Assrt automatically detects the iframe, acquires the frame locator, scopes all interactions to the correct context, and handles the transition timing between questions. You write what you want to test in plain English; Assrt generates the Playwright code that handles the implementation details.
Here is the complete Typeform test suite from this guide, compiled into Assrt scenario format. Each scenario block maps to one of the sections above.
Assrt compiles each scenario block into the same Playwright TypeScript from the preceding sections. The generated code is committed to your repo as standard test files you can read, run with npx playwright test, and modify. When Typeform updates their embed SDK or changes the internal DOM structure, Assrt detects the test failure, analyzes the new DOM, and opens a pull request with updated selectors and wait logic. Your scenario files remain unchanged.
Start with the iframe access scenario. Once that is green, add multi-step navigation, then logic jump branches, then hidden fields, then the thank you screen, then webhook verification. Within a single afternoon you can have complete Typeform embed coverage that would take days to build and maintain by hand.
Related Guides
Ready to automate your testing?
Assrt discovers test scenarios, writes Playwright tests from plain English, and self-heals when your UI changes.