On this page
This page describes how the widget protects your agency and your visitors, and what you must do on your side. It describes design and behaviour that exist; it is not a certification, and we make no claim of regulatory compliance.
Public and private#
| Item | Public? | Notes |
|---|---|---|
Public key (rvk_…) | Yes | It identifies your integration and sits in your page's HTML. It does not authenticate anyone and cannot read private data by itself. |
| Session token | No (per visitor, short-lived) | Created when the chat opens. Opaque, stored only as a hash on the server, never written to a cookie or localStorage, and not shown in the page. |
| Anything secret | Never in the widget | Do not put any secret, password or private API key in widget configuration. The widget needs none. |
| Bot challenge secret | Server side only | Nothing of it is in your page or in the package. The human check runs in a frame from recent-visit.com, which holds the public site key. |
If a public key is copied to another site it does not work there: the page's domain must match the domain registered for the key. If a key is exposed or misused, revoke it in the portal (Website widget → Revoke this key) and register again for a new one.
How access is enforced#
- Domain check. A session is issued only to a page whose origin matches your registered domain (https, default port, the domain or any of its subdomains;
localhostfor Test). The check is repeated on every request, so changing the domain or switching the integration off takes effect immediately. A session is bound to the exact origin that opened it. - The agency comes from the key, never from the request. The browser cannot name an agency, and the request format rejects unknown fields. A tour can only be named if it is your published tour.
- Tenant isolation. Retrieval for the assistant runs with your agency enforced inside the database query, so another agency's documents cannot enter the answer. The assistant has its own tools and instructions and cannot call the Recent Visits marketplace tools.
- Features. The server decides which features (chat, tours, quote) your integration has; page options can only hide them.
- Instructions in documents are data. Text in your Knowledge documents, in tours or in visitors' messages is treated as untrusted reference material. It cannot change the assistant's rules, and the assistant is told never to reveal its instructions or other agencies' information.
- No cookies. Requests are sent with
credentials: 'omit'. Responses can be read only by the registered page (CORS is limited to your origin, never*). - Output safety. Model output is rendered as plain text; links are made only from
httpsaddresses and Recent Visits paths, and open in a new tab withnoopener noreferrer.
Sessions and caching#
- A session token is valid for 30 minutes of inactivity and for at most 12 hours in total; an expired token can still be renewed for a further 5 minutes. The client renews it at about three quarters of its life.
- The look returned by
POST /configis cached on the server for about a minute per integration, so Studio changes appear within about a minute; sessions are always checked live. - The script file is served with
Cache-Control: public, max-age=3600and an open CORS header, so Subresource Integrity works on any site. The API itself never sendsAccess-Control-Allow-Origin: *. - Chat messages are limited to 2,000 characters and request bodies are size-limited before they are read.
Content Security Policy#
If your site sends a Content-Security-Policy header, allow:
| Directive | Allow | Why |
|---|---|---|
script-src | https://recent-visit.com | To load /widget/1/widget.js (or 'self' if you serve a copy yourself). |
connect-src | https://recent-visit.com | For the widget's API calls. |
img-src | The origin of any logo or avatar image you configure | The widget itself needs no image sources. |
style-src | Nothing for most sites | The widget's styles live inside its Shadow DOM. A policy that blocks <style> elements in shadow roots needs 'unsafe-inline' for styles. |
For local development with data-api-base, allow that origin instead. The widget shows no frames.
What data goes to Recent Visits#
- When the page loads: a request for the look (
POST /config) carrying your public key; the browser adds itsOrigin. No visitor data. - When the chat opens: a session request. No cookies are used.
- In a chat: the messages the visitor types, and the page context you chose to share (
pageContext.tourSlug,pageContext.title). The widget does not read or send anything else from your page; it does not scrape page content. - Visitor's name: optional, a display name only.
- Quote form: name, email, message and optional phone, country, date, travellers and budget, sent only when the visitor submits it, with their consent.
- IP address: used for rate limiting like any web service.
- In the browser: by default the session and the visible chat text are kept in the tab's
sessionStorageso a reload keeps the conversation. Usestorage: 'memory'to keep nothing. Invitations store a few flags and timestamps (no text). The widget never uses cookies orlocalStoragefor the session.
Chats and quote requests are saved in Recent Visits and are visible to your agency's team in the portal. Chats that do not become a quote request are deleted after 90 days; chats from the Test environment after 7 days.
Privacy and visitor disclosure#
- The chat opens with a note that the conversation is saved and shared with your agency, and asks visitors not to type their email address or phone number. If one is typed anyway it is removed before it is stored or shown to anyone, and the visitor is told.
- The only place the widget asks for an email or phone is the quote form, which has a consent checkbox ("I agree to share these details with <your agency>"). You see the email and phone only after the visitor accepts one of your quotes.
- An AI generates the replies and can be wrong. By default the widget presents the assistant as AI (its default name is "AI Travel Assistant" and its subtitle "AI travel assistant"), so keep it identifiable as AI if you rename it. Your own policy should not present its answers as binding. A quote from your agency is what commits you.
- Mention the chat in your own privacy policy, and use consent mechanisms your law requires. This guide does not replace legal advice. The widget does not set cookies, but your site's cookie rules still apply to anything else on your pages.
Limits and abuse protection#
Requests are rate limited per network address, per visitor session and per integration, and a daily message budget per integration is set by Recent Visits staff (smaller for Test). When a limit is reached the widget says how long to wait, using the real time until that limit resets (for example "Please try again in about 2 minutes"), keeps the visitor's message, and turns Send off until then. Limits fail closed: if the limiter itself cannot be reached, expensive actions are refused. The values can change and are not part of the public contract.
Human check. Before a session starts, Recent Visits may ask the visitor's browser to pass a Cloudflare Turnstile check (Managed mode: most visitors see nothing; only a suspicious browser sees a checkbox). The widget does this by itself, only when the server asks, in a small frame loaded from recent-visit.com; nothing is added to your page and you do not need a Cloudflare account or key. That frame can only be embedded by the domain registered for your key. Each check passes once: the server verifies it with Cloudflare, accepts it only for this purpose and for recent-visit.com, and never accepts the same token twice. If the check is blocked (for example by a strict content blocker) the widget shows its usual "try again later" message and no session starts.
Performance#
The widget is one script of roughly 50 KB (minified, before compression) with no dependencies, loaded with async, and does nothing visible until it is ready. At load it makes one small request for its look; a session starts only when the visitor opens the chat. While a visitor waits for a person it polls gently (every few seconds, slowing down when nothing changes, and pausing in a background tab).
Reporting a vulnerability#
Use the details on the Contact page and describe what you found and how to reproduce it. Do not include real visitor data.
Last checked against the product:
Related articles
- Agency integration guide · How the widget knows which agency it belongs to, how environments and drafts work, how quote requests reach your portal, and a go-live checklist.
- SDK troubleshooting · Fixes for the widget not appearing, wrong branding or content, options not applying, network and permission errors, Next.js and mobile problems, and quote requests that do not show up.
Still stuck? Contact us and tell us what you tried.