Pre-recorded tooltip tours
"Click Save → then Settings → then this icon" — one fixed path, no eye-contact, no follow-up question.
- Static, pre-recorded path
- Breaks when the UI changes
- One-way — you can't see them
- Same script for everyone
Tooltip tours and modal "Step 3 of 7" walk-throughs can't react to what the user actually sees. Guidewell drops one script tag and lets your team join any visitor's session — shared cursors, click ripples, scroll & navigation sync. The conversation happens on the page, not in a popup.
Static product tours are a guess about what each user might need. They break the moment your UI changes and can't adapt to what the visitor is actually looking at. Guidewell flips it: a real teammate joins the session, sees the same screen, and points with the cursor in real time.
"Click Save → then Settings → then this icon" — one fixed path, no eye-contact, no follow-up question.
Shared cursors, click ripples, scroll & navigation in sync. Free-form, multi-peer, contextual — like sitting next to them.
The widget at the bottom-right of this very page is a real install. Follow the steps below to launch a session and bring in one or more peers — another tab, an incognito window, or a few teammates at once.
Look at the bottom-right corner of this page — there's a round floating button. Click it to open the panel.
A tiny form asks for your name and whether you're getting help or guiding someone. It's remembered locally — next visit there's no form at all.
Press "Copy invite link" — a URL with ?session_id=… is now in your clipboard.
Paste the link into another browser, an incognito window, or send it to multiple teammates at once — every tab that opens it auto-joins. You'll see a separate cursor per peer.
Built for support, sales demos and onboarding flows. Real-time, low-latency, multi-page, and invisible to your end users until they need help.
See exactly where each peer is pointing — every participant gets a unique color (deterministic from their pid). Throttled to 60 fps, normalized to viewport coordinates, gracefully degrading on touch.
Click anywhere outside the widget and a wave fires for every other peer in the room — perfect for "tap this button" instructions without a single voice call.
Pages stay in lock-step even when each user has a different viewport size. Position is sent as a normalized ratio, applied without echoing back.
Works with classic page loads and SPA routers. We patch history.pushState/replaceState so visitor navigation mirrors instantly.
No email, no password, no signup. One tiny form (name + role) on the first visit, then a session ID and a copy-able invite link. Every tab that opens the link joins the same room — bring in as many peers as you need.
N participants per session, no hard cap. Pure broadcast model — every event reaches every other peer. peers_snapshot on join, peer_join/peer_leave updates keep every UI honest about who's there.
Cursors and scroll are realtime-only — they'd flood any DB. We persist only the meaningful stuff: click with coords, navigate with the resolved URL, and any action you fire from your code — straight into gw_analytics_events, scoped to the project & owner.
~7 KB gzipped, vanilla JS, no React/Vue runtime, no external CDN requests. Loads async, won't block your TTI, isolates styles in a scoped host.
One persistent connection per peer, JWT-scoped per session. Server broadcasts a peer snapshot on join so the UI never lies about who's there.
Sessions remember the page they started on. Cross-origin events are filtered server-side; loopback hosts get a developer-friendly bypass.
Brand it in seconds: primaryColor, theme: dark, custom fabIcon (any inline SVG — Lucide, Heroicons, your own).
REST to bootstrap, WebSocket to stream, Postgres to remember. A pure broadcast room with N participants, no hard cap and no master/slave roles — every event from one peer fans out to all the others, and only the meaningful ones land in the database.
POST /v1/sessions with X-Guidewell-Key returns a fresh session_id, an identity_jwt and a signal_token. Server resolves the key into a project_id and owner_user_id and stores them on the row — that's how the admin shows you only your sessions.
Each peer connects to /v1/sessions/{id}/signal?token=…. The server adds them to an in-memory SignalRoom and emits a peers_snapshot with everyone already inside, then a peer_join to all the existing members.
Cursor / scroll / click / nav events from any peer are JSON-broadcast to all the others (sender excluded). peer_leave fires on disconnect. The room is just a list — no participant cap, no role hierarchy, no per-pair signaling.
Cursors and scroll stay in-memory — they'd drown any database at 60 fps. click_wave, nav_change and explicit action events are written to gw_analytics_events with their full payload (coords, target href, custom props). The admin replay is built straight off that table.
Drop the snippet anywhere on your page. The bundle injects its own host element, scopes its styles, creates sessions on demand and tears itself down on unmount — no glue code, no virtual DOM runtime.
data-api points at your backend, data-key binds the session to a project. Everything else has sensible defaults.
data-fab-icon (any inline SVG — paste from lucide.dev), data-fab-text, data-primary-color, data-theme="dark".
window.GuidewellConfig = {…} before the script tag. Same options, useful when you build the config dynamically.
data-guidewell-toggle on any button on your page, or call Guidewell.open() / .close() / .toggle() from your own JS. The two CTAs on this page use exactly that.
<!-- That's the entire install. Same-origin: no data-api needed. --> <script src="/widget.js"></script> <!-- Cross-origin? Point at your API host. The data-key links every session this widget creates to your project + owner row, so the admin console shows you only the sessions you actually own. --> <script src="https://api.your-domain.com/widget.js" data-api="https://api.your-domain.com" data-key="prj_pk_…"></script>
Guidewell ships with a Nuxt-based admin console for project owners and operators — manage projects, watch live sessions, run the API, handle billing & access.
Spin up a new project, get an API key, paste the embed snippet, lock to site_origin, tweak per-project widget defaults — all from the dashboard.
Every session you launched — scoped to your account via owner_user_id, filterable by project_id. Status, origin, mode, started/ended timestamps. Drill in to replay the persisted click / nav / action stream.
Per-project payments ledger with manual or provider-backed entries (Stripe/etc.), currency-aware, export-ready. Wire your own pricing on top.
Invite teammates, assign roles, review who has access to which projects. Admin-only view, JWT-backed, role-aware navigation in the sidebar.
RBAC primitives baked in: control which roles can manage projects, run sessions, see analytics or charge customers — Postgres rows, not config files.
Built-in OpenAPI playground — pick any endpoint, set path params and JSON body, fire it from the admin without touching curl. Live docs included.
No proprietary runtime, no vendor lock-in. Self-host on Fly.io, Render, your own Kubernetes — same Postgres your team already operates.
Python 3.11+, async REST & WebSocket. OpenAPI auto-generated.
Transactional persistence, RLS-ready schema, SQL migrations.
JWT-scoped per-session signaling rooms, peer snapshots on join.
~7 KB gzipped IIFE bundle. Vite build. No frontend runtime.
Single Dockerfile + compose for local dev, prod-ready images.
Vue 3, Tailwind, lucide-vue-next. Built-in i18n & theme switcher.
Spin up the backend, mount the widget, open the admin console. Everything you saw on this page is shipped in this repo — no SaaS sign-up required.