Hogsend is brand new.Try it
Hogsend
Client-side SDK

In-app surveys

Fire an event from this page, answer the NPS card it drops in your feed, and watch a second journey read your score back off the spine — one identity, no login.

This is the same in-app feed surface the nav bell renders — here it's inlined on the page so you can answer a survey without leaving. You are an anonymous visitor: no login, no identify call. Fire the event, answer the card, and the answer routes back through a journey.

Fires demo.survey. The NPS card lands in the feed below — answer it and a journey drops the thank-you item.

Notifications
    src/journeys/docs-inapp-demo.ts
    import { days } from "@hogsend/core";
    import { defineJourney, sendFeedItem, sendSurvey } from "@hogsend/engine";
    import { Events } from "./constants/index.js";
    
    // demo.survey → drop an in-app NPS card the visitor answers in their bell.
    export const demoSurvey = defineJourney({
      meta: {
        id: "demo-survey",
        name: "Demo — In-app survey",
        enabled: true,
        trigger: { event: Events.DEMO_SURVEY }, // "demo.survey"
        entryLimit: "unlimited",                // re-fire freely
        suppress: days(0),
      },
      run: async (user) => {
        await sendSurvey({
          recipient: { anonymousId: user.id }, // your canonical key
          event: Events.DEMO_NPS_SUBMITTED,    // "demo.nps_submitted"
          mode: "nps",
          property: "score",                   // the answer rides here
          prompt: "How likely are you to recommend Hogsend?",
          title: "Quick question 👇",
          minLabel: "Not likely",
          maxLabel: "Very likely",
        });
        // sendSurvey has NO journeyStateId option — replay-safety is auto-keyed off
        // the Hatchet run anchor inside sendFeedItem.
      },
    });
    
    // demo.nps_submitted → a thank-you item echoing the score (closes the loop).
    export const demoNpsAnswered = defineJourney({
      meta: {
        id: "demo-nps-answered",
        name: "Demo — NPS answered → thank-you",
        enabled: true,
        trigger: { event: Events.DEMO_NPS_SUBMITTED }, // "demo.nps_submitted"
        entryLimit: "unlimited",
        suppress: days(0),
      },
      run: async (user) => {
        const raw = user.properties.score; // SurveyBlockView captured it under "score"
        const score =
          typeof raw === "number" || typeof raw === "string" ? String(raw) : "?";
        await sendFeedItem({
          recipient: { anonymousId: user.id },
          type: "survey-thanks",
          title: `Thanks — you scored ${score} 🙏`,
          body: "You answered an in-app survey. That emitted demo.nps_submitted onto the spine — a journey read your score and dropped this.",
          actionUrl: "https://hogsend.com/docs/client-side/survey",
          journeyStateId: user.stateId, // sendFeedItem DOES accept this
        });
      },
    });

    What just happened

    The button called client.capture("demo.survey", {}) — a first-party event keyed to your anonymous id.

    A journey triggered on demo.survey and called sendSurvey({ mode: "nps", property: "score", event: "demo.nps_submitted" }). That published a feed item carrying a survey block, which FeedItemView auto-renders as an NPS card via SurveyBlockView.

    Answering the card captured demo.nps_submitted with your score under the score property (SurveyBlockView writes { [property]: value, feedItemId, source: "in_app" } and reuses an idempotencyKey so a re-answer is exactly-once). It lands in user_events.properties like any other first-party event.

    A second journey triggered on demo.nps_submitted, read user.properties.score, and called sendFeedItem — the thank-you item that echoes your number. Same write-back path a real NPS or CSAT loop uses.

    The aggregate is queryable off the same events:

    GET /v1/admin/reporting/breakdown?event=demo.nps_submitted&property=score&metric=nps

    The whole round-trip used one identity. A pk_ publishable key has no user token, so userId stays null and the feed stays keyed to your anonymous id end to end.

    On this page