Skip to content

Keep page feedback from readers who decline cookies - #480

Open
eugenia-scandit wants to merge 4 commits into
mainfrom
feat/docs-feedback-no-consent
Open

eugenia-scandit wants to merge 4 commits into
mainfrom
feat/docs-feedback-no-consent

Conversation

@eugenia-scandit

Copy link
Copy Markdown
Collaborator

The page feedback widget ("Was this page helpful?") sends votes and comments to PostHog, which only loads after a reader accepts cookies. A reader who declines and then writes a comment currently leaves no trace of it.

What

  • Fallback for refused captures: when PostHog refuses the event, the comment is posted to a configurable endpoint (an Apps Script Web App that appends it to a spreadsheet). It's sent only when PostHog refused, never alongside a successful capture, so a consenting reader's comment isn't recorded twice.
  • What it sends: the four fields the widget already sends to PostHog (page URL, page title, vote, comment). No identifier and nothing derived from the reader. A missing vote is sent as null, never as "not helpful".
  • How it's sent: no-cors with a text/plain body, because an Apps Script Web App doesn't answer a CORS preflight. The response is opaque, so this reports that the request was sent, not that it arrived. The widget's copy already promises only "sent".
  • Configuration: the endpoint and token come from DOCS_FEEDBACK_ENDPOINT and DOCS_FEEDBACK_TOKEN at build time (customFields in docusaurus.config.ts). Both default to empty, which disables the fallback; with them unset, the widget behaves exactly as today. The token ships in the client bundle, so it only deters drive-by scanners; the receiving script must validate and rate-limit.

Before this does anything in production

  • The receiving Apps Script Web App must be deployed with anonymous access, and it should validate the payload and enforce a daily cap.
  • DOCS_FEEDBACK_ENDPOINT and DOCS_FEEDBACK_TOKEN must be set in the production build environment.
  • Please confirm with whoever owns privacy and consent that storing anonymous comments without cookie consent is acceptable. No cookie or identifier is involved.

Checks

  • npm run build passes; tsc is clean.

🤖 Generated with Claude Code

@github-actions

github-actions Bot commented Oct 7, 2026 •

Copy link
Copy Markdown
PR Preview Action v1.8.1

🚀 View preview at
https://Scandit.github.io/data-capture-documentation/pr-preview/pr-480/

Built to branch gh-pages at 2026-10-13 09:53 UTC.
Preview will be ready when the GitHub Pages deployment is complete.

Comment thread src/components/PageFeedback/index.tsx Outdated
): Promise<boolean> {
if (!endpoint) return false;
try {
await fetch(endpoint, {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This needs a privacy/consent review: the disclosure no longer matches where the data goes. For a reader who declined cookies, this sends the comment, page URL and title to script.google.com, and the request carries their IP and user agent. That's a different processor and different storage (a spreadsheet) than the consent banner covers. The widget's note (index.tsx:376) still says the comment is "sent to our analytics tool with this page's address", which is no longer accurate on this path.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Partly addressed, still open: this needs a privacy/consent sign-off.

The disclosure now matches the destination (7c8da0b, 5507dce): on the fallback path, the note says the comment, the vote and the page's address and title go to a Google Apps Script form that adds them to a spreadsheet, and that the request carries the browser's IP address and user agent. On the analytics path, the note is unchanged.

What code can't settle: a reader who declines the cookie banner is exactly who the fallback sends to. That's the point of this PR, so someone responsible for privacy and consent needs to confirm it's acceptable before this ships.

Comment thread docusaurus.config.ts Outdated
// Set from the environment so a redeploy of the Web App (which changes the
// URL) needs no code change, and so a fork or a preview build does not
// silently post into the production sheet.
feedbackEndpoint: process.env.DOCS_FEEDBACK_ENDPOINT ?? "",

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No build sets DOCS_FEEDBACK_ENDPOINT or DOCS_FEEDBACK_TOKEN. build-docs.yml (line 61) and docs-preview.yml run yarn build with no env block, so in production this is '', sendDirectFeedback returns false, and the fallback ships turned off. Please add the variables (as secrets or vars) to the deploy workflow, or this PR has no effect.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still open: the variables don't reach production yet.

I added DOCS_FEEDBACK_ENDPOINT (repo variable) and DOCS_FEEDBACK_TOKEN (repo secret) to the build step of build-docs.yml, for main only, and previews never get them (docs-preview.yml, and docusaurus.config.ts forces both to empty when preview_build is set). But build-docs.yml only builds and tests; nothing in this repo deploys the live site. So the pipeline that builds production must set these two variables too, or the fallback stays off. Who owns that pipeline? Until it's configured, merging this changes nothing for readers.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, and sorry: my original comment pointed you at the wrong workflow. docs.scandit.com is built and published by generate-docusaurus-documentation-production in the data-capture-sdk GitLab project, on an hourly schedule. It clones main here and runs npm run build.

I opened a GitLab MR that passes the two variables to that job only: https://gitlab.scandit.com/mobile/data-capture-sdk/-/merge_requests/39858

  • It maps DOCS_FEEDBACK_ENDPOINT_PROD and DOCS_FEEDBACK_TOKEN_PROD to the names docusaurus.config.ts reads. The staging job runs the same script, so it doesn't get them and can't post into the production sheet.
  • A GitLab maintainer still has to create those two CI/CD variables. Ideally do that before this PR merges: the production job skips the build while the docs commit is unchanged, so variables added later only take effect with the next commit to main.
  • The env: block in build-docs.yml doesn't affect production. Keeping it is fine, but the comment above it shouldn't suggest it's what turns the fallback on. Dropping it would also let you remove the GitHub repo variable and secret.

I'll leave this thread open until the GitLab side is configured.

Comment thread src/components/PageFeedback/index.tsx
Comment thread src/components/PageFeedback/index.tsx Outdated
Comment thread src/components/PageFeedback/index.tsx Outdated
Comment thread src/components/PageFeedback/direct.ts
eugenia-scandit and others added 4 commits October 13, 2026 10:45
The feedback widget sends votes and comments to PostHog, which only loads
after a reader accepts cookies. A reader who declines and then writes a
comment currently leaves no trace of it.

When PostHog refuses the capture, the comment is now posted to a
configurable endpoint instead (an Apps Script Web App that appends it to
a spreadsheet). It is sent only when PostHog refused, never alongside a
successful capture, so nothing is recorded twice. The payload is the four
fields the widget already sends (URL, title, vote, comment), with no
identifier. The vote stays three-valued: a missing vote is sent as null,
not as "not helpful".

The endpoint and token come from DOCS_FEEDBACK_ENDPOINT and
DOCS_FEEDBACK_TOKEN at build time. Both default to empty, which disables
the fallback and leaves the widget behaving exactly as before.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The analytics helper now reports why a capture did not happen: PostHog
not loaded, the reader opted out, or PostHog threw. The boolean helper
other components use keeps its exact behaviour. The feedback widget posts
a comment to the fallback endpoint only when PostHog is not loaded; an
opted-out reader's comment is never sent anywhere.

The note under the comment box now says where a comment will go before
the reader sends it. When the fallback applies, it names the Google Apps
Script form and spreadsheet, the page address and title, and that the
request carries the browser's IP address and user agent.

Submitting is guarded against a second send while one is in flight, and
Send is marked disabled meanwhile. After the request settles, the
current outcome is read from a ref, and nothing updates the widget if it
has unmounted.

Failure and success copy follow the path taken: a PostHog refusal keeps
the "analytics is turned off or blocked" text; a failed fallback request
says the connection failed or was blocked. Because the fallback uses
no-cors and cannot see the response, its thanks says only that the note
was sent.

The endpoint and token are passed to the build of the main branch only.
Pull-request builds get empty values, and preview builds force the
fallback off in the config.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Otherwise the vote could also reach PostHog if the reader accepted
cookies a few seconds later, and be recorded twice.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@eugenia-scandit
eugenia-scandit force-pushed the feat/docs-feedback-no-consent branch from 9c8795e to 20aa16d Compare October 13, 2026 09:50

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants