Security and troubleshooting

What is public and what is checked, content security policy, limits, and every error code with what to do.

Security#

  • The key is public. The lfk_... key is in your page's source. It only identifies the form, and it only works from the websites on the form's allowed list.
  • Getting a new key. On the Install tab, New key gives the form a new key. The old one stops working at once, so update the snippet on your website straight away.
  • The website check. Every request carries the key, and Subcontext checks that the page's website (its origin, meaning https:// plus host plus port) is on the allowed list.
  • No cookies or logins. The form sends no cookies and needs no secret. The only token it uses is the short-lived chat token.
  • Nothing secret goes in your page. There is no secret key for the lead form. Never put an API token (for the server API) in a web page.
  • Bots. The form turns away most bots without asking the visitor anything. A bot that is caught gets the same answer as a person.
    • Drawn forms have a hidden trap field that people never see.
    • Drawn forms that are sent unrealistically fast (in under a second) are dropped.
    • Built-in check (Install tab, Bot checks). Turn it on if spam still gets through. The form solves a small puzzle in the background while people fill it in. Visitors don't see or click anything, it works with screen readers, and nothing about the visitor is kept. The puzzle makes sending in bulk slow and costly for bots. createLead solves it before sending, so your own form uses it too.
    • Cloudflare Turnstile is supported for forms Subcontext has set it up for. Ask Subcontext if you need it.
  • Links. data-success-url and data-privacy-url must start with http: or https:. Anything else (like javascript:) is ignored.
  • Privacy in logs. What visitors type is not written to Subcontext's request logs.

Content security policy#

If your website sends a Content-Security-Policy header (a list of where your pages may load things from), add these:

Directive Allow Why
script-src https://js.subcontext.com The form script (and the chat script, if the form opens a chat after sending).
connect-src https://subcontext.com Loading the form, sending leads, the bot check and Results counts.
connect-src wss://subcontext.com Only if the form opens a chat after sending: the chat's live connection.
style-src your nonce on the script tag, or 'unsafe-inline' The form's styles and accent colour are added as <style> elements carrying the script tag's nonce. Or use styles: false (an accent colour still needs the nonce).
script-src and frame-src https://challenges.cloudflare.com Only if your form uses Cloudflare Turnstile.

A nonce is a random value your server makes for each page and puts in both the header and the tag:

html
<script nonce="RANDOM" src="https://js.subcontext.com/leadform-latest.js" data-key="lfk_YOUR_KEY" defer></script>

Limits#

  • Sends per visitor: 10 leads in 10 minutes from one IP address. After that the visitor sees "You've sent this a few times. Please wait a few minutes and try again." (code rate_limited).
  • Bot check puzzles: 30 in 10 minutes per IP address.
  • Results counts: 120 in 10 minutes per IP address.
  • Values: up to 1,000 characters each, 5,000 for message, and 40 extra keys per lead.
  • Waiting: a send that gets no answer in 15 seconds counts as a timeout (and is retried once).

People sharing one internet connection (an office, for example) share these limits.

Troubleshooting#

Problems are always written to the browser console, starting with Subcontext.leadform. Add data-debug="true" to the script tag to see more.

If a drawn form can't load, it shows "This form isn't available right now. Please try again later." and the console says the form couldn't load (<code>): <message>. If the campaign is paused, the form shows "This form isn't taking enquiries at the moment."

Error codes#

code and message are what you get in the result (and in onError).

Code HTTP status Message What it means and what to do
no_key No lead form key: add data-key="lfk_..." to the script tag, or pass key to init(). No key anywhere. Check data-key on the script tag.
invalid_key 401 Unknown lead form key. The key is wrong, or the form was given a new key. Copy it again from the Install tab.
form_disabled 403 This lead form has been turned off. Turn the form on (on the form's page, Turn on).
not_entitled 403 This account can't take leads right now. The Subcontext subscription has lapsed.
origin_not_allowed 403 This website isn't on the lead form's list of allowed websites. Add your website exactly (https://, host, port) on the Install tab. Pages opened straight from your computer (file://) never work. Serve the page from a web server.
campaign_paused 409 This form isn't taking enquiries at the moment. Make the campaign active.
campaign_archived 409 This form isn't taking enquiries at the moment. The campaign is archived. Use a form on an active campaign.
invalid 422, or before sending Please check the highlighted fields. Look at result.fields for each field's message. Very rarely the message is "That couldn't be sent. Please try again." instead.
challenge_failed 422 That didn't go through. Please send it again. The bot check's answer was out of date or already used. The script has already tried again once.
turnstile_failed 422 Please complete the check that you're not a robot, then send again. Cloudflare Turnstile only.
rate_limited 429 You've sent this a few times. Please wait a few minutes and try again. Over 10 sends in 10 minutes from one IP address. Wait and try again.
network We couldn't send that. Check your connection and try again. No answer at all. The visitor is offline, or the request was blocked by your content security policy or an ad blocker. Already retried once.
timeout We couldn't send that. Check your connection and try again. No answer in 15 seconds. Already retried once.
server 5xx Something went wrong on our side. Please try again in a moment. Already retried once. If it keeps happening, contact hello@subcontext.com.
no_target head mode needs a target element: init({ mode: "head", target: "#my-form" }) init({ mode: 'head' }) with no target, or a target that isn't on the page yet. Nothing is drawn.

By symptom#

  • Nothing appears and there's no error. Check that the element has the attribute data-subcontext-leadform. If you use init(), pass a target that is already on the page when init runs.
  • The form appears on first load but not after moving around a single-page app. Call Subcontext.leadform.mountAll() after adding the element.
  • Subcontext is undefined. Your code ran before the script loaded. Use the whenLeadform helper in Set it up from JavaScript.
  • origin_not_allowed on one version of your site. https://example.com and https://www.example.com are different websites, and so are http://localhost:4100 and http://127.0.0.1:4100. Add each one you use.
  • The form says "This form isn't taking enquiries at the moment." The campaign is paused or archived. Make it active.
  • Settings from init() are ignored by Subcontext.createLead. The shortcut has no settings. Call submit on the handle init() gave you.
  • invalid from your own form with nothing obviously wrong. Subcontext checks designed fields you send (their choices, lengths, formats, and that a checkbox field gets a clear yes or no). Look at result.fields.
  • Some of your own consent answers aren't recorded. Only the box keys from consent() count, only boxes the form shows, and only clear yes or no words. Unticked boxes are never sent.
  • The chat doesn't open. The form needs a live agent under After it's sent, the send must have succeeded, a success page can't be set, and your content security policy must allow wss://subcontext.com.
  • The lead arrived but nobody got an email. Set who gets one on the Design tab (Email each enquiry to, up to 5 addresses). A lead that was retried is the same lead, so it doesn't send a second email.
  • Nothing shows on the Results tab. Only drawn forms are counted, and not if data-analytics="false" is set.

Need help?#

Email hello@subcontext.com.

Stuck, or something missing?

Get in touch and a person on the team will help.

Contact us