Verify page
Fromenance is a communication provenance platform, and the verify page is the second way a customer can ask “did you send this?”: they paste the message, upload the .eml, upload a screenshot, or type the reference code on a page on your domain and the verdict renders on the page. It needs no mailbox, no reply identity, and no account.
By the end you will have a site key bound to your page’s origin, the widget on yourdomain.com/verify in your branding, and a verdict rendering on the page.
Where the page lives
Section titled “Where the page lives”The page is yours: northfieldbank.example/verify or any URL on an origin you allow. Fromenance serves only the script and an optional iframe document from cdn.fromenance.com; there is no hosted verify page on fromenance.com, and the customer never sees the Fromenance name. The widget posts to api.fromenance.com/v1/public/submit with your site key and renders the response in your branding.
1. Create a site key
Section titled “1. Create a site key”Admin app: Verify page, New site key, name it, and add the allowed origins. Or:
curl -X POST https://api.fromenance.com/v1/site-keys \ -H "Authorization: Bearer fr_live_..." \ -H "Content-Type: application/json" \ -d '{"name":"Public verify page","allowed_origins":["https://northfieldbank.example","https://www.northfieldbank.example"],"normal_rate_per_minute":60}'| Field | Notes |
|---|---|
public_key |
sk_pub_.... Public by design; it is bound to the origins below, so it is useless elsewhere |
allowed_origins |
Up to 20 full origins (https://host). Requests whose Origin is not in the list are rejected |
normal_rate_per_minute |
5 to 6,000, default 60. Above this rate the key requires a Turnstile token (see below) |
turnstile_required |
true requires Turnstile on every submission |
theme |
Free form key value pairs used by the admin app preview |
The response includes embed.script and embed.iframe, ready to paste, and the admin app shows a live preview of the widget with your name, logo, and accent colour from Settings, Branding.
2. Embed the widget
Section titled “2. Embed the widget”Script tag (recommended)
<div id="fromenance-verify"></div><script src="https://cdn.fromenance.com/verify.js" data-site-key="sk_pub_..." data-target="#fromenance-verify" data-institution="Northfield Bank" data-theme="auto" async></script>Attributes:
| Attribute | Notes |
|---|---|
data-site-key |
Required |
data-target |
CSS selector of the container; a div is inserted before the script when omitted |
data-institution |
The name shown in “Did this message come from Northfield Bank?” |
data-theme |
light, dark, or auto (follows the visitor’s system setting) |
data-accent |
Button and link colour, for example #0f4c81. The verdict card also picks up the accent set in Settings, Branding |
data-turnstile |
Your Cloudflare Turnstile site key, needed when the key is or can become Turnstile gated |
data-api |
Only for staging; defaults to https://api.fromenance.com |
The script also exposes window.Fromenance.mount({ siteKey, target, institutionName, theme, accent, turnstileSiteKey, onVerdict }) for single page applications, and window.Fromenance.version.
Iframe
<iframe src="https://cdn.fromenance.com/embed.html?key=sk_pub_...&name=Northfield%20Bank&theme=auto" title="Verify a message" style="width:100%;min-height:520px;border:0"></iframe>Query parameters mirror the data attributes: key, name, theme, accent, turnstile, api. The iframe posts two messages to the parent window: { type: "fromenance:height", height } whenever its content height changes, so you can resize it, and { type: "fromenance:verdict", verdict } after each answer. The allowed origin check applies to the page that embeds the iframe, so add your site’s origin to the site key, not cdn.fromenance.com.
What the customer sees
Section titled “What the customer sees”A message textarea, an optional reference code field, an optional field for the address that received the message (recommended, since the recipient is half of the strongest match), and file inputs for an .eml or a screenshot (PNG, JPEG, WebP, up to 6 MB). Text and .eml answer in under three seconds; screenshots show “Reading the screenshot” while OCR runs and answer within about fifteen seconds.
The verdict card carries your logo, the outcome label (Verified, Not verified, Known fraud), the locked verdict text, a next step that includes your fraud contact, and a link to your support URL. Outcomes use the same three colours as the admin app and nothing else in the widget uses them.
Handling the verdict on the page
Section titled “Handling the verdict on the page”Pass onVerdict to mount() or listen for the iframe message to record analytics or route the customer:
window.Fromenance.mount({ siteKey: "sk_pub_...", target: document.querySelector("#fromenance-verify"), institutionName: "Northfield Bank", onVerdict: (v) => { analytics.track("verify_result", { outcome: v.outcome, rule: v.rule, submission: v.submission_id }); if (v.outcome === "known_fraud") location.assign("/security/report-fraud"); },});The verdict object is the same one the verify page API returns.
Rate limits and Turnstile
Section titled “Rate limits and Turnstile”- 60 submissions per minute per IP address and 600 per minute per site key. Over the limit the API answers
429withRetry-Afterand the widget shows “Too many checks right now”. - When a site key exceeds its
normal_rate_per_minute, or hasturnstile_requiredset, the API answers428 turnstile-required. The widget then loads Cloudflare Turnstile with the site key fromdata-turnstile, and resubmits with the token once the challenge passes. Withoutdata-turnstilethe customer sees “Please complete the security check” and cannot continue, so set it if your page can see bursts.
Privacy on the web path
Section titled “Privacy on the web path”The address the customer types is hashed with your tenant secret to compare against registrations, stored encrypted only so the submission can be linked to a later forward, and purged 30 days after the verdict. Uploaded .eml files and screenshots are stored encrypted under your tenant prefix and follow your retention setting. The widget never sets cookies.