Skip to main content
A journey is one flow in your product that has a clear start, a clear success, and ways to fail. Examples are connecting an integration, checkout, submitting onboarding, and inviting a teammate. Your code reports four events for it: the journey started, the customer attempted an action, an attempt failed, and the journey succeeded. When the customer opens a support conversation during a journey, the ticket arrives with that journey attached. The Inbox shows the journey’s name, where it stood when the customer wrote, where it stands now, how many attempts and failures there were, and the latest failure. The investigation reads the same events in the session timeline.

Requirements

  • @gethinto/browser-sdk 0.5.0 or later for journeys. Help offers need @gethinto/browser-sdk 0.8.0 or later, and @gethinto/native-support-react 0.5.1 or later for the React slot.
  • Capture that knows the signed-in customer, through initialIdentity or bindConversationIdentity with { kind: "external_id", value: user.id }. Hinto Signal sets this up. Without a signed-in customer, journey() returns a handle that does nothing and, with debug: true, logs why.

Report a journey

Call journey(key) where the flow begins. Call attempt(action) in the submit handler, before the request. Call fail(...) in the error branch you already have. Call succeed() only after your server confirms the result, never on click.
journey(key) is idempotent while the journey is open. It returns the open instance for that key in this tab, or starts a new one. The instance lasts through reloads and redirects in the same tab, so a flow that leaves for an OAuth provider and comes back is still one journey. After succeed(), the next journey(key) starts a new instance. Two tabs track two instances.

When a submit control can be disabled

A disabled button emits no click, so the customer can try to submit and nothing happens. If your form disables its submit control while it is invalid, report the attempt from a wrapper that sees the attempt, and say how the customer was told:
  • feedback: "inline": the error appears next to the field or the control.
  • feedback: "summary": the error appears in a banner, toast, or summary at the top.
  • feedback: "none": the customer saw nothing.

Offer help on the journey

Reporting a journey alone shows nothing to the customer. When the journey’s events suggest the customer is stuck, for example after repeated failures, Hinto Signal decides whether to offer help. The offer appears only where your product placed a slot for it. Without a slot, Hinto still records the decision, but the customer never sees it. With the React kit, place <Support.HelpOffer> next to the step the journey covers, under your Support.Provider:
  • journey is the same key you pass to journey(key), or an array of keys.
  • topic names the step in the customer’s words. It fills the card’s title and the message that Contact support sends.
  • onRetry is the step’s existing handler. Without it, the card has no Try again button.
  • Keep the slot mounted. Do not wrap it in a condition. It renders nothing until support has started for a signed-in customer and there is an offer, and it shows the offer only while it is on screen.
  • Place one slot per journey on a screen, on the screen where the customer fails. A slot on a different page never shows the offer.
The card has three actions. Contact support sends one message in the customer’s words that carries the journey, and opens your support view. Try again runs onRetry. Not now hides the offer. Nothing is sent to your team until the customer chooses Contact support. The slot sits on your product page, outside the conversation. Theme tokens you set on the conversation’s class do not reach it. Set them on :root or on a class you pass as the slot’s className, and pass theme="dark" in dark mode. Customization lists the tokens. Hinto decides when to offer help. Repeated failures, a missing prerequisite or permission, a rejected input, or a failure the customer never saw can bring an offer. Your team controls it in Hinto under Settings > Hinto Signal: Proactive help turns offers on or off for each journey, and Offer limits sets how long an offer stays, how long to wait between offers, and how many a customer sees in a week. A customer who chooses Not now is not offered help on that journey again for the quiet period.

Offer help without the React kit

With @gethinto/browser-sdk/conversation alone, for example inside your own chat, read runtime.offers and draw the offer yourself:
  1. offers.subscribe(listener) and offers.snapshot() give the current offer. Signal checks for one only while something is subscribed, the page is visible and online, and the customer has an open journey.
  2. When the snapshot’s status is "eligible", call offers.show(id) and draw the offer only when it returns "ok". That records the impression. "closed" means the offer is gone, and "unavailable" means the call did not complete. After a reload, a "shown" status means draw it again without calling show. "none" means there is no offer.
  3. Not now calls offers.dismiss(id).
  4. Contact support calls offers.contact(id, { message }) with a sentence in the customer’s words. On "started", call runtime.open(), which sends it. While that message is on its way, contact answers "unavailable" and a typed send answers "busy".
  5. After journey.succeed(), call await offers.refresh() so the offer goes away at once.
With session capture only, there is no conversation, so there are no offers.

Choose the journey

Instrument a flow your product already has. Add calls to its existing handlers, and do not add product behavior, server routes, or test hooks to make it fail. If the flow is a stub, or has no real point where it succeeds or fails, leave it without a journey. Pick one flow first. A good first journey:
  • happens while the customer is signed in,
  • has an explicit success that your server confirms,
  • fails in ways customers write to support about.
Connecting an integration is usually the best choice, because its success is explicit and journeys survive the OAuth redirect.

Vocabulary

Key, action, and category are tokens: lowercase letters, digits, and underscores, starting with a letter, at most 39 characters. stripe_connection, connect, and third_party are tokens. The Inbox shows the key as a label: stripe_connection reads as “Stripe connection”. Failure categories. Map your errors to one of these: Feedback is none, inline, or summary, as described above.

Limits

Metadata is for tokens such as a plan name or a provider, never for customer data. The SDK redacts metadata strings with the same patterns it uses for every payload, and an event whose metadata has a key that looks like a secret, such as password, api_key, or tokens_used, keeps its step and drops all of its metadata. Journeys never carry free text: a failure has a category, not a message. See Privacy controls.

Check it

Run the flow once, the natural way, with debug: true in initHinto. You do not need to make it fail. The SDK writes its debug lines with console.warn and a [Hinto] prefix, so they appear as warnings, not errors. The SDK logs one ingest response: accepted N, duplicates N, rejected N line per batch, and a batch can hold journey events and other capture together. In the browser’s Network tab, find the /v1/ingest request whose body contains the journey events. The journey works when the response line for that batch shows rejected 0. A rejected event is dropped on its own and never blocks other capture, so a nonzero count means a key, action, category, or metadata value broke a rule above. To check the help offer slot, open the screen where the journey runs and confirm the page has an element with data-hinto-part="help-offer". It is empty until there is an offer. To see the card without making the flow fail, render the slot with the kit’s testing fixture and call controls.presentOffer({ journey }). The package’s AGENT_INSTALL.md describes the fixture. If the journey reports correctly but a stuck customer never sees an offer, the slot is missing, is on a different screen, or was off screen while the offer was open. Proactive help may also be off for the journey, or the customer may have reached an offer limit.

In the Inbox

When a signed-in customer sends a Native Support message during a journey, the ticket links that journey. The first message that links it records how far the journey had progressed, so the Inbox can say “failing when they wrote”. Events that arrive later fill in the history, and a later success changes the current outcome. The block is labeled Reported by your app, because journey events come from your browser code and a customer could forge them. Tickets without journeys look the same as before.