Tripworks is a booking and CRM platform for tour and activity operators. Its leads table lists people in the order they arrived, so sales reps dial down the list and spend their best hours on the wrong people. I designed an Intent Scorer for it: a feature that watches how a shopper behaves on the operator's booking site, turns that into a 0–10 intent score, and moves the hottest leads to the top of the CRM so reps know who to call right now. The video above is the working prototype: a shopper browses a mock operator site, abandons checkout, and appears at the top of the CRM with a score of 9.2.
My role: a solo concept project. I defined the feature, the scoring model, the CRM changes and the demo story, and built the interactive prototype with Claude Code.
1. What is the problem statement?
Tours are impulsive, time-boxed purchases ("what are we doing on Saturday?"). When a shopper picks a date, types their email and then closes the tab, they have told the operator what they want, when, and how to reach them. A call within minutes usually answers the question that stopped them: pickup, kids' ages, weather, group price. A call the next morning often reaches someone who has already booked elsewhere.
- For reps: every lead looks the same in the CRM. A newsletter sign-up and a checkout abandoner sit side by side, sorted by date.
- For operators: checkout abandoners are the easiest revenue to recover, and today nothing flags them.
- The brief: turn website behaviour into one number reps can trust, put it where they already work, and make the whole idea obvious to someone watching a 60-second demo with no narration.
Speed-to-lead matters more for tours than almost anywhere else: the shopper who abandoned checkout ten minutes ago is the one to call first.
2. What are the tradeoffs considered?
- Explainable rules vs a trained model. A model trained on past bookings would rank better eventually, but reps only follow a ranking they believe, and there's no history to train on at launch. I chose a transparent weighted score first, designed so the same five signals can later feed a logistic regression without changing the interface.
- Which signals, and how much each counts. Five signals: return visits, experience clicks, pages researched, booking clicks (Book Now, Check Availability, Select Date) and abandoned checkouts. Booking clicks carry 30% of the score and abandonment 25%, because they are the clearest buying signals. The other three get 15% each.
- Caps vs raw counts. Without caps, one shopper clicking the same card fifty times would outrank someone who tried to pay. Each signal is capped (for example 10 card clicks, 3 booking clicks), so no single behaviour can dominate.
- A new screen vs changing the existing one. A separate "hot leads" dashboard is one more place reps have to remember to check. I added an Intent column, a "Hot Leads Right Now" KPI card and an Intent filter to the existing leads table, made the intent score the default sort, and matched the CRM's own cards, pills and spacing so the feature looks native.
- How loud to be. Fire emojis make tiers readable at a glance, from Cold to Call Now. Only leads scoring 8 or more get the pulsing red "Call now" badge and a phone button, so the alarm stays meaningful.
3. What is the solution proposed?
- Capture. A tracking snippet on the operator's booking site records each behaviour and ties the anonymous visitor to a real person once they type an email at checkout.
- Score. Each signal is normalised against its cap, weighted, and summed to a 0–10 score: score = Σ min(value ÷ cap, 1) × weight × 10. The score maps to six tiers: Cold, Warm, Interested, Hot, Very Hot and Call Now.
- Rank. The CRM sorts leads by intent by default. When a new high-intent lead arrives, it enters at the bottom of the table and climbs to #1, the "Hot Leads Right Now" count ticks up, and the notification bell lights up.
- Explain. Clicking a score opens a drawer with a bar for each signal's contribution, the full website timeline, and a plain-English reason to call, such as "Viewed Kayaking 9 times across 4 visits, clicked Check Availability twice, Select Date once and Book Now once, and abandoned checkout just now."
- Measure. The metrics the feature should move are lead-to-booking conversion, time-to-first-contact for leads scoring 8 or more, and revenue per rep hour. The test plan is an A/B test across rep cohorts: intent-sorted ordering against the default ordering, with scores logged silently in the control group so the score's calibration can be checked.
In the demo, the shopper (Alex) arrives with three earlier visits and a score of 4.8, Cold. They compare kayaking and hiking, check availability, click Book Now, type their email and close the tab. That takes them to 9.2, Call Now, and to the top of the CRM a few seconds later. The code is on GitHub: github.com/badrinarayanmohan/intent-scorer.
4. Any other improvements I could have done?
- Learn the weights from real bookings. Once there is history, I'd train a logistic regression or gradient-boosted model on which leads actually booked, and calibrate the score so a 9 means a real probability.
- Let old behaviour fade. An abandonment from ten minutes ago is urgent; one from three weeks ago isn't. Recency decay would re-rank leads as their activity ages.
- Use more context. Party size, how far away the tour date is, price tier, traffic source and live availability would all sharpen the score. A sold-out Saturday should lower the urgency.
- Handle identity and consent properly. Production needs stitching across devices and sessions, and no tracking before consent where the law requires it.
- Test with real reps. The prototype runs on mock data. A pilot with one operator's sales team would show whether reps follow the ordering and whether the "why call now" line is the right amount of detail.