Skip to main content
This quickstart adds a feedback form that looks and behaves like the rest of your product. You own the interface; Glean Feed receives each request for triage, roadmap planning, and—when you choose—publication on your portal. If you are still choosing an integration, start with the Headless SDK overview. There are two ways to send a submission. Pick based on where your code runs:
  • Server proxy — the safe default. Your app posts the feedback to your backend, and your backend forwards it to Glean Feed with an API key. The key never touches the browser.
  • Browser-direct, signed. For convenience, the browser can submit directly using a customer-specific signed user token from identify. No workspace secret or API key ships to the client.
Browser code is visible to your customers, so never put an API key (gf_live_… / gf_test_…) in client-side JavaScript. If you can run server code, prefer the server proxy. Use browser-direct only with a signed user token, never a raw key.

Before you start

Which board a submission lands on decides whether it’s public or private — feedback inherits its board’s visibility. Omit the board and it goes to your first submittable (public or private) board. There’s no separate “make this public” flag; choose the board and its settings do the rest.

Quickstart: submit through your server

Your form posts to an endpoint you own. That endpoint forwards the request with a Glean Feed API key. This is the recommended path because the credential stays on your server and your application decides which signed-in customer is making the request. Create an API key with feedback:write, then keep it in a server-only environment variable. See Authenticate API requests for key creation and storage guidance.
Post { "title": "Dark mode please", "body": "A dark theme would help at night.", "pageUrl": "https://app.acme.com/settings", "requestId": "request-123", "deliveryId": "delivery-456" } from your form to /give-feedback. Reuse deliveryId only when retrying that exact HTTP operation. A successful call returns the created Glean Feed request. Open Feedback in your Glean Feed dashboard and confirm that the title, customer, source URL, and metadata are present. For the full request and response schema, see POST /feedback. The submitter is unverified — your server vouches for it, and the API key is the trust boundary. Glean Feed finds or creates a customer profile from the email or externalId so repeat submitters converge on one profile. Omit submitter entirely for anonymous feedback. Creating a submitter for the first time counts toward the workspace’s tracked customer limit. At the limit, POST /feedback returns 403 forbidden for a new submitter. Existing submitters continue to work, and omitting submitter still creates anonymous feedback. Do not retry a new submitter until the workspace has available capacity or upgrades. source.externalId is the durable identity of the record in the source system. Replaying the same workspace, source kind, and external ID with the same feedback returns the original request instead of creating a duplicate. Reusing that identity with different feedback returns 409 conflict and does not alter either request. This is separate from Idempotency-Key, which protects retries of one API operation and returns that operation’s cached response before source-conflict evaluation. Use a distinct delivery-attempt key when you need both protections. When you send both fields and the email is already reserved by workspace team history or another signed identity, Glean Feed preserves the submitter as an externalId-only customer instead of merging identities. If you send only an email that belongs to team history, the request is rejected; include a stable customer externalId or omit submitter for anonymous feedback.
A no-login “Give feedback” button on a static or marketing site — where you have no signed-in customer — should still go through your server (or a serverless function) with the API key. A public, no-key browser endpoint for fully anonymous capture is coming separately; until then, the server proxy is the anonymous path.

Alternative: submit directly from the browser

If you already sign customers in with identify, the widget holds a signed user token and can submit directly — no backend round-trip, no secret in the client. Prerequisite: call init with your workspaceId, then identify the customer (the signature is computed on your server with your widget secret — see identify).
Using a bundler? Import the helper and pass the token yourself:
Or call the endpoint directly — it sends permissive CORS headers, so you can fetch it from any origin:
Browser-direct submissions are attributed to the signed-in customer and follow the same rules as the portal: they land on submittable (public/private) boards, respect invite-only membership, and default to pending review so your team approves before anything appears publicly.

React

Same two options, wrapped in a component. Both render your own form and show a submitting/submitted state — using the framework you already have. Server proxy (recommended). The component posts to your backend, which forwards it with the API key (see the server quickstart). No Glean Feed secret touches the browser.
Browser-direct, signed. If you already identify customers, import the helper and pass the signed userToken — no backend round-trip, still no long-lived secret in the client.

Source context is private

Everything in source is triage context for your team — it is stored separately from the public request and appears only in the authenticated dashboard. It is never returned by public feedback API reads or rendered on the public portal, even when the feedback lands on a public board. Only the title and description follow the board’s visibility. The older top-level sourceUrl and metadata fields remain accepted for existing integrations, but new server integrations should send the nested source object. Credential-like metadata keys, embedded URL credentials, tokens, raw payloads, and message history are rejected. Store only the small source facts your team needs to triage the request.

Limits

Validation runs before anything is written, so oversized payloads fail fast and nothing is stored. Browser-direct JSON requests are capped at 1 MiB of encoded data; larger requests return 413. Capture endpoints are rate-limited. Server-proxy traffic is limited per API key and per workspace; browser-direct is limited per customer and per IP. On a limit you’ll get a 429 — back off and retry. Submissions inherit your board’s moderation settings, so pending items wait for approval before they’re publicly visible.