Manage Forms

Setting Up Embed-Only AccessPro

How to block direct access through the survey link and collect responses only from the survey embedded on your website.

How to set it up

Go to the Embed tab

Click the ⚙️ icon in the top right of the editor to open survey settings, then select Embed from the tab list on the left.

Turn on embed-only access

Turning on Embed-only access lets you pick one of three modes.

ModeWhat it blocksWhat you needPlan
Allowed sites onlyEmbeds on sites outside the allowlist, direct link accessAllowed originsPro
Host-signed tokenThe above + non-browser requestsAllowed origins, signing secret, host server integrationEnterprise
Host-signed token + member identificationThe above + duplicate responses per memberThe above + member ID in the tokenEnterprise

1. Allowed sites only

Blocks embeds on non-allowed sites and direct access from the browser. This is the simplest setup. However, server-to-server requests can imitate the same headers. If you need to verify who the respondent is, use one of the signing modes below.

2. Host-signed token

The form opens only with a token signed by your server — even for non-browser requests. Imitating headers won't get through.

3. Host-signed token + member identification

Uses the member ID carried in the token to block duplicate responses per member. In this mode, the duplicate response summary on the Respondents tab also shows "External member ID" as a criterion. You can limit responses to one per member without asking respondents for separate email or phone verification.

Enter allowed origins

Enter the address of the site where the survey will be embedded.

  • Enter the scheme and host only. https://your-site.com
  • Do not include a trailing slash or a path. https://your-site.com/survey is invalid.

Before you continue

In Allowed sites only mode, the gate applies only once you add at least one origin. If the list is empty, no restriction is enforced — always double-check.

Issue a signing secret

Choosing a signing mode reveals the Signing secret section. This is the value your host server uses to sign tokens.

1. Issuing it for the first time

Click Issue secret and the secret value is shown once. Click Copy right away and store it somewhere safe, such as an environment variable on your host server.

Take care

This value is never shown again. If you didn't copy it, you'll have to reissue it — and reissuing immediately invalidates existing tokens.

2. Reissuing it

If a secret already exists, the button changes to Reissue secret. Clicking it opens a confirmation dialog. Reissuing behaves as follows.

  • Tokens signed with the current secret are rejected immediately.
  • Every host that signs embed tokens must be switched to the new secret.
  • Sessions that are already open stay valid until they expire (up to 2 hours).

Reissue only after your host server deployment is ready. If the order slips, respondents won't be able to open the form in the meantime.

Host server integration

In the signing modes, your host server must create a short-lived JWT for each visitor and pass it to the embed.

TermMeaning
Signing secretA value issued per form. Your host server signs tokens with it.
TokenA short-lived JWT your host server signs for each visitor.

Storing the signing secret

Save the secret you copied in an environment variable on your host server.

WALLA_EMBED_SECRET=paste_the_copied_value_here

Before you continue

Never put the signing secret in a browser bundle, frontend code, or a repository. If it leaks, anyone can forge tokens. Secrets are per form, so if you embed multiple forms, store each one separately.

Signing a token

Sign a fresh token on the server every time a visitor opens the page. Here's an example using jose.

import { SignJWT } from 'jose';

const secret = new TextEncoder().encode(process.env.WALLA_EMBED_SECRET);

const token = await new SignJWT({ email: user.email })
  .setProtectedHeader({ alg: 'HS256' })
  .setSubject(user.id)          // required in member identification mode
  .setAudience('{formId}')      // the Walla form ID
  .setExpirationTime('5m')
  .sign(secret);

In Host-signed token mode, .setSubject(...) is not required. In Host-signed token + member identification mode, the member ID must be placed in sub.

Token rules

ItemRequirement
algOnly HS256 is allowed.
Signing keyUse the UTF-8 bytes of the signing secret string.
audMust equal the form ID. If it's an array, it must contain the form ID.
expRequired, and no more than 10 minutes in the future. 5 minutes is recommended.
subRequired in member identification mode, and must be 255 characters or fewer.
emailOptional.
EncodingUse base64url characters (A-Za-z0-9_-).

Passing the token to the iframe

You can copy the base embed code from Share → Embed code in the dashboard.

Signing modes

Pass the token in the URL fragment (#).

<iframe
  src="https://form-address/f/{formId}#embedToken=signed_token"
  width="100%"
  height="500"
  style="border:0"
  loading="lazy">
</iframe>

Before you continue

Do not send the token in the query string (?embedToken=). Query strings can end up in server access logs and Referer headers. Always use the fragment (#embedToken=).

Allowed sites only mode

This mode does not require a token.

<iframe
  src="https://form-address/f/{formId}"
  width="100%"
  height="500"
  style="border:0"
  loading="lazy">
</iframe>

Enter only the scheme and host for allowed origins, like https://your-site.com. Do not include a trailing slash or a path.

The session after passing the gate

Once the gate is passed, the result is kept for 2 hours. During that time respondents can refresh the page without a new token.

Integration flow

In the signing modes, the form opens in this order.

  1. Check that the user is signed in to your service.
  2. Sign a token with the signing secret you were issued. In member identification mode, include the member ID in the token.
  3. Open the form with the signed token carried in the URL fragment.
  4. Walla verifies the token's signature and origin, then displays the form.

Troubleshooting

Pre-launch checklist

  • Confirmed the mode you want is supported on your current plan.
  • Entered only the scheme and host for allowed origins.
  • Stored the signing secret only in host server environment variables.
  • Created a fresh token per request with a 5-minute lifetime.
  • Put the correct form ID in aud.
  • Included sub in tokens for member identification mode.
  • The iframe passes the token in the fragment (#embedToken=).
  • Verified on the real embed page that the form opens and submits correctly.

When to use this

  • You embedded a survey on an internal portal or member page and want to stop the link from leaking outside
  • Only members of your service should be able to respond
  • You want one response per member, but making them go through email verification is too much friction

On this page