Who you spoke to and how the message must sound. The city drives the German sign-off (“Beste Grüße nach …”), the send time drives the thank-you opener.
Create a private app in HubSpot (Settings → Integrations → Private Apps) with the scopes crm.objects.contacts.read and crm.objects.companies.read, then paste its token here. It is stored in this browser only.
A · The app already runs on Cloudflare Pages from Git — the easy case.
functions/hubspot/[[path]].js is already in the repository. Pages picks up anything under functions/ at the repo root automatically — there is no code editor to find in the dashboard, and no separate Worker to create./hubspot/…, which is same-origin — CORS never even applies.https://<your-domain>/hubspot/crm/v3/objects/contacts. A JSON error about a missing Authorization header is the good answer — it proves the proxy is live. A 404 means the deployment has not picked it up yet.B · Anywhere else — opened from a file, served from localhost, or hosted somewhere without Functions.
hubspot-proxy, then Deploy.deploy/hubspot-proxy-worker.js from this project, then Deploy again.ALLOWED_ORIGINS with the origins that may call it, comma-separated, e.g. https://followup-studio.cxlever.io,http://localhost:8777.https://hubspot-proxy.<subdomain>.workers.dev) into this field.ALLOWED_ORIGINS, separated by commas, and paste the same URL into each app. The Worker holds no token of its own, so nothing is shared between the apps except the route.Already connected a Worker to Git and it will not take variables? Cloudflare then says “Variables cannot be added to a Worker that only has static assets” — wrangler deploy found no wrangler.toml, so it published the repository as files instead of running the script. Route A makes that Worker unnecessary; disconnect or delete it.
Either way the proxy stores nothing and holds no secret. Your private app token travels in the request header from this browser, exactly as it would to HubSpot directly, and only read paths are forwarded — a leaked URL cannot write into your CRM.
The message can only be as deep as what you paste here. Block A is mandatory; B and C are what make the mirror paragraph land — every fact the AI uses from them is listed back to you in the internal note.
Nothing you paste leaves this browser unless you press Generate in the Live Generate panel — and then it goes straight to the AI provider you chose, never to a CxLEVER server.
The preset decides the architecture of the message — which blocks appear, in which order, and how long each piece may be.
For the deepest messages, paste this prompt into one of the latest top models — e.g. Claude Opus 4.8, Gemini 3.1 Pro, GPT-5.x or Mistral Large — then paste the JSON it returns into the Spec editor below.
The message set as JSON — the file everything else is rendered from. You rarely need to open this: generate below, edit in the preview. It is here for writing a message by hand, for pasting JSON back from an AI, and for reading the error when something does not parse.
Runs the same prompt against your own AI provider. Everything is optional — the app works fully offline without it. Keys are stored only in this browser and sent directly to the provider you pick, over HTTPS. Nothing else leaves your machine.
Scores the message set against the CxLEVER follow-up rules — salutation, capitalised Du-forms, forbidden phrases, double punctuation, bullet symbols, sign-off, length, one CTA — plus a hallucination check that flags every number and every product or vendor name in the message that appears nowhere in your inputs.
Your standing rules. They go into every prompt and every quality check, so the app enforces the same style each time.
Keep your own tone-of-voice prompts here and pick the one this message should follow. The AI receives the profile name, the link and — if you paste it — the text itself. Paste the text: no AI can open your Google Doc from inside this app.
Save snapshot stores a dated copy of the current message set with its quality score. Diff shows exactly what changed against the set you have open now — useful to compare the draft you generated with the one you actually sent. Snapshots live in this browser only.
Self-test of the app's dependencies and current config. No data is sent unless you click “Test connection” above.
Release over one of the three input blocks. Several files at once are fine — each is appended under its own filename.