綺和美
KIWABI · Concierge × Hair Quiz

How the Concierge learns from the quiz

When a customer takes the hair quiz, the Concierge remembers their answers and uses them to give personal recommendations.

1
📝

Customer takes the quiz

The AI Hair Test on the KIWABI site (built by Tangent).

2
🗂️

The quiz records

Their answers, plus who they are (their email, if shared).

3
🤝

Handed to the Concierge

Live in the same visit, or saved for a return visit.

4

Personalized result

Right products, in-context answers, a smoother sale.

Step by step

1
A customer takes the AI Hair Test

on the KIWABI site. That quiz belongs to Tangent.

2
The quiz captures two things

their answers (hair type, concerns) and who they are (their email, if shared).

3
That result is handed to the Concierge

so it is not starting from scratch, it already knows this person's hair profile.

4
The Concierge personalizes

it greets them by their results, recommends the right products, and answers in context.

5
The loop closes

quiz interest becomes a guided, personal conversation that is far more likely to end in a sale.

Two phases, so we can start fast

Phase 1 · this week

Same-visit handoff

The quiz and the Concierge talk to each other right on the page. The moment someone finishes the quiz, the Concierge picks it up. Light build, no plumbing.

Phase 2 · durable

Remembered next time

We also save each result, so a customer who took the quiz last week is recognized when they return, and the team can see the data.

What we need from Tangent

1A way to know who is who

Ideally the customer's email, so the answers match the right person.

2A signal when the quiz is finished

So the Concierge knows the right moment to step in.

3A way to send us the answers

Live on the page, or delivered to us behind the scenes.

4Consent & ownership confirmed

The customer agreed to this use, KIWABI owns the data, Tangent holds it for KIWABI.

Our privacy promise

We only ever read the data, only the fields the customer agreed to share, kept to the minimum needed — and KIWABI stays the owner of it the whole way through.

Technical appendix

For the engineering teams

Two integration paths. The client-side bridge ships first; the webhook adds durability and returning-visitor lookups.

0 · The join key (decides everything)

Same-visit personalization needs no identifier (the bridge hands off in the browser). Recognizing a returning visitor needs a stable, cross-session id: email ideally, or a persistent first-party id both sides can read on the page. A per-visit session id does not match across visits. Anonymous submissions are analytics-only.

1 · Client-side bridge — same session, no backend

Both widgets share the page. On quiz completion, hand the result straight to the Concierge. Ask Tangent how completion is signaled: a window event, an iframe postMessage, a completion callback, or a dataLayer push. Bridge data is a same-visit hint (user-forgeable); the signed webhook is the source of truth for anything stored.

// custom-event example
window.addEventListener('tangent:quiz_complete', (e) => {
  const r = e.detail || {};
  window.KiwabiConcierge?.setContext({
    source: 'ai_hair_test',
    submissionId: r.submissionId,
    email: r.email || null,
    profile: r.profile || r.result,       // hair type, concerns, segment
    recommendations: r.recommendations,   // products shown
    takenAt: r.completedAt
  });
});

// iframe variant — verify origin first
window.addEventListener('message', (e) => {
  if (e.origin !== 'https://TANGENT-DOMAIN') return;
  if (e.data?.type === 'quiz_complete') { /* same handoff with e.data.payload */ }
});

2 · Webhook — durable, returning visitors, analytics

POST https://<concierge-host>/api/quiz/tangent · Content-Type: application/json
Auth:  HMAC-SHA256 of the raw body with a shared secret, header X-Tangent-Signature: sha256=<hex>. TLS only. Fallback: bearer token.

Payload we ask Tangent to send:

{
  "submission_id": "tan_9f2...",           // unique, for idempotency
  "occurred_at": "2026-07-08T17:05:00Z",
  "quiz": { "id": "ai_hair_test", "version": "3" },
  "identity": {
    "email": "jane@example.com",           // the join key, if consented
    "shopify_customer_id": null,
    "session_id": "sess_abc",              // correlate to the on-site session
    "visitor_id": "vis_123"
  },
  "answers": [
    { "id": "hair_type", "q": "Hair type?",    "a": "wavy" },
    { "id": "concern",   "q": "Main concern?", "a": "thinning" }
  ],
  "derived": { "segment": "thinning-wavy", "recommendations": ["Root Vanish"] },
  "consent": { "marketing": true, "at": "2026-07-08T17:04:40Z" },
  "market": "US", "locale": "en-US"
}

Receiver rules: verify the signature (401 if bad) · upsert by submission_id so retries are safe · store keyed by identity · return 200 fast and process async · Tangent retries any non-2xx with backoff.

@app.post("/api/quiz/tangent")
async def tangent_quiz(request):
    raw = await request.body()
    if not hmac_ok(raw, request.headers.get("X-Tangent-Signature"), SECRET):
        return JSONResponse({"error": "bad signature"}, 401)
    upsert_quiz_submission(json.loads(raw))   # idempotent on submission_id
    return {"ok": True}

3 · How the Concierge consumes it

On a Concierge session, resolve identity (Shopify login email, or the on-page session/visitor id), look up the latest submission, and inject a compact profile into context: "AI Hair Test: wavy, concern = thinning, segment = thinning-wavy, shown Root Vanish." The Concierge personalizes from stored facts only. It never invents a hair profile, and if none is on file it simply asks.

4 · Security & reliability

TLS onlyHMAC-verifiedread-only consented fieldsPII minimizedidempotentretriable

KIWABI is the data owner and Tangent is the processor. The shared HMAC secret is generated on our side and handed over securely, never in email or chat.

Phase A stores nothing new. Phase B is gated on a short data-processing note, consent that covers Concierge personalization, and an agreed retention/deletion policy before any customer data flows.

Full implementation guide for engineers  →