Skip to content

Hooky docs

Hooky adds a chat bubble to your sites. Your visitors message you, you reply from your dashboard or your phone, and you count what counts: signups, orders, clicks.

Getting started

  1. Create your account with Google or a link sent by email. No password. You’re asked for your first site: its name and address.
  2. In Sites, open your site and copy the install prompt. Paste it into the tool that builds your site, or into your AI assistant.
  3. Publish your site: the bubble shows up at the bottom of the screen. Messages land in Messages.

The prompt works in any tool that writes code:

  • Claude
  • ChatGPT
  • Codex
  • Claude Code
  • Lovable
  • Bolt
  • v0
  • Cursor
  • Replit
  • Windsurf

And on any site where you can add a <script> tag: Framer, Webflow, WordPress, Shopify, a hand-coded site…

Even quicker: ask your AI to do it all. “Create a Hooky account with my email lila@example.com and install the bubble on https://example.com.” See Create an account from an AI.

Install the bubble

With a prompt

The easiest way. Your dashboard gives you this prompt with your site’s key already in it:

Add the Hooky chat bubble to this site, on every page.

Paste this tag once, just before </body>, in the HTML template shared by every page (index.html for a React or Vite app, app/layout.tsx for Next.js, using the Script component from next/script with strategy="afterInteractive"):

<script src="https://heyhooky.com/widget.js" data-site-key="SITE_PUBLIC_KEY" async></script>

Do not change the script URL or the data-site-key attribute. Do not add any other code: the bubble shows up by itself at the bottom of the screen.

With Claude, ChatGPT or Codex, paste it into the conversation where you work on your site: the AI hands you back the edited file, or edits it itself if it has access to your code.

By hand

One line, just before </body>, on every page:

<script src="https://heyhooky.com/widget.js" data-site-key="SITE_PUBLIC_KEY" async></script>

With Next.js (App Router), in app/layout.tsx:

import Script from "next/script";

export default function RootLayout({ children }) {
  return (
    <html lang="en">
      <body>
        {children}
        <Script src="https://heyhooky.com/widget.js" data-site-key="SITE_PUBLIC_KEY" strategy="afterInteractive" />
      </body>
    </html>
  );
}

The public key (data-site-key) identifies your site. Anyone can see it in the page’s code: that’s expected. You’ll find it in Sites, under the prompt.

Script tag options

AttributeMeaning
data-site-keyRequired. The site’s public key.
data-langOptional. The bubble’s language: fr, en, es, pt, it or de. Without it, the bubble follows the page’s language (<html lang>), then the browser’s, and English by default.

Color, side of the screen (right or left) and welcome message are set in Sites, with a live preview. Changes apply without touching your site’s code.

Site addresses

AI tools often publish your site on their own address (my-site.lovable.app, my-site.vercel.app…) before your real domain. Add every address in Sites: conversations and stats stay in one place.

  • As long as no address is declared, the bubble works everywhere.
  • Once there’s one, the bubble and stats only work on the addresses in the list. Nobody can use your key anywhere else.
  • www. doesn’t count: example.com also covers www.example.com.
  • To test locally, add localhost (any port). A page opened as a file (file://) has no address: serve it with a small local server.
  • On an address that isn’t allowed, or with a key that no longer exists, the bubble just stays hidden.

Open the bubble from a button

Once the bubble has loaded, your page can open or close it:

<button type="button" onclick="window.Hooky && Hooky.open && Hooky.open()">Contact us</button>

Hooky.open();   // opens the bubble
Hooky.close();  // closes it

Handy for a “Contact us” button in your menu or at the bottom of a product page.

Stats in the page

Count what happens on your site with Hooky.track. Call it right after the action has succeeded:

// Someone signs up
Hooky.track("signup");

// A purchase: value is summed (an amount)
Hooky.track("purchase", { value: 49 });

// With details
Hooky.track("purchase", { value: 49, product: "vase", delivery: true });

Cards show up in Stats, site by site, over 7, 30 or 90 days, in your time zone.

With your AI

You don’t have to write this code. Ask for it, or copy the full prompt from the Stats tab:

Add Hooky conversion tracking to this site. The Hooky bubble is already installed (widget.js script tag from heyhooky.com).

Call Hooky.track("event_name") right after the action has succeeded:
- signup: after the account is created;
- purchase: after payment, with the amount: Hooky.track("purchase", { value: 49 });
- contact: after a form is sent.

If this code can run before widget.js has loaded, first add in the <head>:
<script>window.Hooky=window.Hooky||{q:[],track:function(n,d){this.q.push(["track",n,d])}};</script>

Do not send any personal data (no email, name or phone number) in the properties.

Before the bubble has loaded

The bubble loads async: if your code calls Hooky.track very early, first add this line to the <head>. Events are queued, then sent as soon as the bubble is there.

<script>window.Hooky=window.Hooky||{q:[],track:function(n,d){this.q.push(["track",n,d])}};</script>

Rules

FieldRule
NameFree text, 64 characters max. Lowercased, and spaces become _. Letters, digits and _ . : - only. "Newsletter Signup" becomes newsletter_signup.
valueOptional. A number, summed in the card (an amount, a quantity). Without value, a single numeric property is used instead.
PropertiesOptional. 20 max, flat: strings (500 characters max), numbers or booleans. They show up in the latest events.
Rate limit120 events per minute per visitor.

Never send personal data (email, name, phone, address) in an event. Count actions, not people.

Stats from a server

Some events are only known server-side: a payment confirmed by Stripe, a signup created by your API. Send them with the site’s secret key.

curl -X POST https://api.heyhooky.com/v1/events \
  -H "Authorization: Bearer hks_your_secret_key" \
  -H "Content-Type: application/json" \
  -d '{"name": "purchase", "value": 49, "properties": {"product": "vase"}}'

The secret key

It starts with hks_. The owner and admins find it in Sites, on the site’s page, under “Secret key (server)”, and can regenerate it: the old key stops working right away. Keep it on your server (in an environment variable), never in your page’s code or in a public repo.

The request

FieldMeaning
nameRequired. The event name (same rules as in the page).
valueOptional. A number, summed.
propertiesOptional. A flat object, 20 keys max.
occurred_atOptional. When the event happened, in ISO 8601 (2026-10-04T14:30:00Z), up to 7 days in the past. Otherwise, now.

Responses

StatusMeaning
201Saved. The body returns the event: {"event": {"id", "name", "value", "properties", "source": "api", "occurred_at"}}.
401{"error": "invalid_secret_key"}: missing, wrong or regenerated key.
422{"error": "invalid", "errors": {…}}: empty or malformed name, too many or nested properties.
429More than 600 events per minute for this key. Try again a bit later.

Examples

Node.js (18 or later):

await fetch("https://api.heyhooky.com/v1/events", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.HOOKY_SECRET_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ name: "purchase", value: 49 }),
});

Python:

import os, requests

requests.post(
    "https://api.heyhooky.com/v1/events",
    headers={"Authorization": f"Bearer {os.environ['HOOKY_SECRET_KEY']}"},
    json={"name": "purchase", "value": 49},
    timeout=5,
)

In a Stripe webhook (checkout.session.completed), the amount paid is session.amount_total / 100.

Channel: receive notifications

Every site has a channel, a bit like a Slack channel you only read: your server, Stripe, Zapier, GitHub, a cron… post notifications to it, and you read them in Channels, live, with a notification on your phone. Nobody replies.

The channel speaks the Slack incoming-webhook format: any tool that can “send to Slack” can send here. Its address is in Sites, on the site’s page, or in Channels (“Channel address” button).

curl -X POST https://api.heyhooky.com/hooks/hkc_channel_key \
  -H "Content-Type: application/json" \
  -d '{"text": "*New order*: €49 :tada:", "username": "Shop"}'

The channel address isn’t public: anyone who has it can write to it. Call it from your server, not from the page, and regenerate it if it leaks (the old one stops right away). The owner and admins can see it.

The message

FieldMeaning
textThe message, in Slack mrkdwn (4,000 characters max). Required unless blocks or attachments provide one.
usernameOptional. Who is speaking (“Shop”, “Stripe”, “CI”). Otherwise, the site name.
attachmentsOptional. Cards, as in Slack: color (good, warning, danger or #RRGGBB), pretext, title, title_link, text, fields (title, value), footer. 10 cards max.
blocksOptional. The Slack blocks header, section (with fields), context and divider, flattened to text.

The body can be JSON (whatever the Content-Type) or a form with payload=<json>, like Slack. Response 200 {"ok": true}; 400 no_text without a message; 404 if the address no longer exists; 429 beyond 60 messages per minute. Messages are kept 90 days.

Formatting

*bold*   _italic_   ~strike~   `code`   ```code block```
<https://example.com/admin/123|See the order>   <https://example.com>
> a quote
- a list
:tada: :rocket: :warning: :white_check_mark: :moneybag:

Write &amp;, &lt; and &gt; to show &, < and >, like Slack.

With your AI

In Channels, the “Channel address” button gives you a prompt to paste into the tool that builds your site: it sends a notification for every order, signup or form, from the server, with no personal data.

With an API key, GET /v1/sites returns each site’s channel address (channel_url).

Create an account from an AI

No account yet? Your AI can create one for you, then install the bubble right after. Just tell it:

Read https://heyhooky.com/llms.txt, then create a Hooky account with my email lila@example.com and install the bubble on https://example.com

What happens next:

  1. The AI calls the Hooky API with your email and your site’s address. The account and the site are created immediately, with a default API key.
  2. It gets the site’s <script> tag and installs it. The bubble works right away: messages wait for you.
  3. You get an email, “Your Hooky account is ready”. Click Activate my account (the link is valid for 7 days) and log in with Google or a link sent by email.
  4. Answer your visitors on the web (the dashboard, which also works on your phone) or in the Hooky app for iPhone, iPad, Mac and Android (coming soon to the App Store and Google Play).

The email proves the address is really yours: the AI never gets the activation link, the API key or the messages. Without activation, the account and its messages are deleted after 7 days.

The request

curl -X POST https://api.heyhooky.com/v1/agent/signup \
  -H "Content-Type: application/json" \
  -d '{"email": "lila@example.com", "site_url": "https://example.com", "locale": "en"}'
FieldMeaning
emailRequired. The person’s email address: the activation link is sent there.
site_urlRequired. The site’s address, which becomes its first allowed address.
domainsOptional. More allowed addresses (10 max): the tool’s preview address (my-site.lovable.app), localhost to test locally.
site_name, account_nameOptional. Otherwise, taken from the address (example.com → “Example”).
localeOptional. The email’s language: fr, en, es, pt, it or de.

Response 201: the account (status: "pending_activation"), the site with install.script_tag and install.instructions, the address the activation link is sent to, and next_steps, the steps to tell the person. Errors: 422 (invalid_email, invalid_site_url), 429 (too many requests, or three accounts already waiting for activation for this email).

The API with a key

An API key (hka_…) opens your account to a script or an AI: creating sites, reading their install tag and the stats, sending events. Every account gets one when it’s created. The owner and admins manage them in Developers: create one per use, revoke them.

An API key opens the whole account. Keep it server-side (HOOKY_API_KEY), only give it to an AI that works on your code, and revoke it if it leaks.

curl https://api.heyhooky.com/v1/sites \
  -H "Authorization: Bearer hka_your_api_key"
RequestMeaning
GET /v1/accountThe account, its plan, the number of sites.
GET /v1/sitesThe sites, with their public key, their secret key, their channel address (channel_url) and install.script_tag.
GET /v1/sites/:idOne site.
POST /v1/sitesCreate a site: {"url": "https://example.com"} or {"name", "domains": […]}, with optional color, position, greeting. 402 plan_limit beyond the plan.
PATCH /v1/sites/:idChange a site: name, color, position, greeting; domains replaces the allowed addresses, add_domains adds to them.
GET /v1/statsStats: site_id, days (7, 30 or 90), time_zone (Europe/Paris by default).
POST /v1/eventsAn event, with site_id added (or the site’s secret key, without site_id).

Errors: 401 invalid_api_key (missing, wrong or revoked key), 404 (a site of another account), 429 beyond 300 requests per minute.

Answering visitors

  • Visitors write without creating an account. They can leave their first name and email.
  • All your sites land in one inbox, Messages, live. You can filter by site.
  • Tab open, you get a sound and the unread count in the title; tab closed, a browser notification, if you allowed it.
  • Notifications from your tools (orders, deployments…) land in Channels, one per site: see Channel.
  • A message stays unread for a few minutes? An email alerts your team. On the other side, if the visitor left their email before leaving, your reply reaches them by email, with a link that reopens the conversation on your site.

Team and plans

An account groups your sites, their conversations, their stats and your team. You can belong to several accounts and switch between them.

RoleCan
OwnerEverything, including the subscription and deleting the account.
AdminAll sites: manage them, see the secret key and API keys, invite the team.
MemberThe sites given to them: reply and see stats, without editing anything.

Invite people with a single-use link, valid for 7 days, from Team.

PlanSitesPeoplePrice
Free11€0
Creator101€9 / month
Studio505€29 / month

Every plan includes the bubble, stats, several addresses per site and the API. Subscribe on the web, by card with Stripe, in Subscription, or in the app, through the App Store or Google Play, at the same price: one subscription per account. A year costs ten months (€90 or €290).

Data and privacy

  • The bubble sets no cookies. It keeps the visitor’s conversation token in the site’s localStorage, to find the conversation again on their next visit.
  • It lives in a Shadow DOM: your site’s styles don’t distort it, and it doesn’t touch yours.
  • Stats don’t track anyone: they count the events you send, with no visitor identifier.

For AIs

These docs also exist in Markdown, a format AIs read directly:

Give one of these addresses to Claude, ChatGPT or Codex: “Read heyhooky.com/llms.txt, create a Hooky account for me and install the bubble on my site.” Soon, an MCP server will let Claude Code, Codex or Cursor install Hooky by themselves.