The Feedforward Widget
A <30KB feedback widget that drops into any site.
What it is
The Feedforward widget is a tiny, self-contained survey surface built with Preact. It renders inside a closed Shadow DOM, so the host page’s styles can’t leak in and the widget’s styles can’t leak out — it looks the same on every site. It ships no external fonts and no heavy dependencies, so it stays well under the 30KB budget.
- Preact runtime, no framework bloat on the host page
- Closed Shadow DOM for full style isolation
- System font stack — zero web-font requests
- Async, non-blocking load that never delays your page
Installation
Drop this one-line script tag anywhere in your page and you’re live:
<script
src="https://widget.getfeedforward.com/v1.js"
data-embed-key="pk_live_..."
data-survey-id="srv_..."
async
></script>Find your embed key and survey id in the dashboard under Settings → Install.
Configuration
Customize behavior with data-* attributes on the script tag:
data-embed-key— your public embed key (required)data-survey-id— which survey to show (required)data-locale— language override, e.g.en,fr,dedata-api— override the API base URL (self-hosting only)
Programmatic API
When you need control, the widget exposes a small global. Trigger it from a button, a route change, or after a purchase:
// Available on window once the script loads
Feedforward.show(); // open the survey
Feedforward.hide(); // dismiss it
Feedforward.identify("user_42"); // attach a known user idSecurity
Because the widget runs on untrusted host sites, the server trusts nothing it sends. Sessions are authenticated with HMAC-signed embed tokens (short-lived, replay-protected), and every cross-frame message is validated against its origin before it is ever processed.
- HMAC-signed, 1-hour embed tokens with per-token replay protection
- Origin-validated
postMessageon every listener - Visitor IPs are never stored raw — only hashed
Performance
Every kilobyte is accounted for. The bundle is under 30KB gzipped and is enforced in CI on every commit — it can’t silently grow.
- <30KB gzipped, hard-gated in CI
- No
evaland no dynamicFunction() - Loads async — zero impact on your page’s first paint