Review & Referral Request System - Complete Implementation Guide
Automatically request reviews on Google/Yelp after sales, ask for referrals, and re-engage past customers for repeat business.
Technology Stack
Expected Results
Review & Referral Request System
Reviews and referrals are your most valuable marketing assets. This system automates the ask so you never miss an opportunity to grow your reputation and get new customers.
Why Automation Matters
Manual follow-up fails because:
- Inconsistency - Some customers get asked, others don't
- Timing - You forget or reach out too late
- Awkwardness - Asking in person feels weird
- Scale - Can't personally ask every customer
The right ask at the right time makes all the difference.
System Architecture
┌─────────────────────────────────────────────────────────────┐
│ Customer Transaction Completed │
│ Sale closed | Service delivered | Invoice paid │
└───────────────────────┬─────────────────────────────────────┘
│
↓
┌─────────────────────────────────────────────────────────────┐
│ Satisfaction Check (Day 1-3) │
│ "How was your experience?" │
└───────────────────────┬─────────────────────────────────────┘
│
┌─────────┴─────────┐
↓ ↓
┌──────────────────┐ ┌──────────────────┐
│ Happy (Score 4-5)│ │ Unhappy (1-3) │
└────────┬─────────┘ └────────┬─────────┘
│ │
↓ ↓
┌──────────────────┐ ┌──────────────────┐
│ Review Request │ │ Recovery │
│ (Day 3-7) │ │ Workflow │
│ → Google │ │ → Manager Alert │
│ → Yelp │ │ → Fix Issue │
│ → Facebook │ │ → Follow-up │
└────────┬─────────┘ └──────────────────┘
│
↓
┌──────────────────┐
│ Referral Request │
│ (Day 7-14) │
│ → Ask for names │
│ → Incentive offer│
└────────┬─────────┘
│
↓
┌──────────────────┐
│ Re-engagement │
│ (Ongoing) │
│ → Seasonal │
│ → Anniversary │
│ → New services │
└──────────────────┘
Step-by-Step Implementation
Step 1: Trigger Setup
Transaction Complete Trigger:
// Option 1: GHL Pipeline Stage Change
const triggers = {
pipeline: "sales_pipeline",
stage: "completed",
conditions: {
hasEmail: true,
hasPhone: true,
transactionValue: { $gt: 0 },
},
};
// Option 2: Payment Received
const paymentTrigger = {
event: "invoice_paid",
delay: "24_hours", // Wait for delivery/service
};
// Option 3: Service Completed (manual or from field software)
const serviceCompleteTrigger = {
event: "service_completed",
customField: "service_date",
};
Step 2: Satisfaction Check
Initial Check Message:
const satisfactionCheck = {
timing: "day_1_to_3", // After transaction
channel: "sms",
message: `Hi {{firstName}}! This is {{companyName}}. How was your experience with us? Reply with a number 1-5 (5 being excellent).`,
followUp: {
noResponse: {
timing: "day_2",
message: `Hi {{firstName}}, just checking in - we'd love to hear how things went! Reply 1-5.`,
},
},
};
// Process response
const processSatisfactionScore = async (contactId, score) => {
const numScore = parseInt(score);
if (numScore >= 4) {
// Happy customer - proceed to review request
await addTag(contactId, "satisfied_customer");
await scheduleReviewRequest(contactId, "day_3");
// Acknowledge
await sendSMS(
contactId,
`Thank you so much! We're thrilled you had a great experience. 😊`,
);
} else {
// Unhappy customer - recovery workflow
await addTag(contactId, "needs_recovery");
await triggerRecoveryWorkflow(contactId, numScore);
// Acknowledge
await sendSMS(
contactId,
`We're sorry to hear that. A manager will reach out shortly to make this right.`,
);
}
};
Step 3: Review Request Sequence
Request Messages:
const reviewRequestSequence = {
day3: {
channel: "sms",
message: `{{firstName}}, glad you had a great experience! Would you mind leaving us a quick Google review? It really helps small businesses like ours: {{googleReviewLink}}`,
},
day5: {
channel: "email",
subject: `Quick favor, {{firstName}}?`,
body: `Hi {{firstName}},
Thanks again for choosing {{companyName}}!
If you have 2 minutes, we'd really appreciate a Google review. It helps other customers find us and lets our team know they're doing great work.
👉 Leave a review: {{googleReviewLink}}
Thanks so much!
{{senderName}}`,
},
day7: {
channel: "sms",
condition: "no_review_yet",
message: `Last reminder, {{firstName}}! If you haven't had a chance to leave a review, here's the link again: {{googleReviewLink}} - Thanks!`,
},
};
Smart Review Routing:
const getReviewLink = (customer) => {
// Route to platform based on customer source/preference
const reviewLinks = {
google: `https://g.page/r/YOUR_PLACE_ID/review`,
yelp: `https://www.yelp.com/writeareview/biz/YOUR_BIZ_ID`,
facebook: `https://www.facebook.com/YOUR_PAGE/reviews`,
};
// Default to Google (most valuable for SEO)
let platform = "google";
// If they found you on Yelp, ask for Yelp review
if (customer.source === "yelp") {
platform = "yelp";
}
// Rotate to spread reviews across platforms
if (customer.reviewCount % 5 === 0) {
platform = "facebook";
}
return reviewLinks[platform];
};
Step 4: Review Tracking
// Monitor new reviews via Google API
const checkForNewReviews = async () => {
const response = await fetch(
`https://mybusiness.googleapis.com/v4/accounts/${ACCOUNT_ID}/locations/${LOCATION_ID}/reviews`,
{ headers: { Authorization: `Bearer ${GOOGLE_ACCESS_TOKEN}` } },
);
const reviews = await response.json();
// Find new reviews since last check
const newReviews = reviews.filter(
(r) => new Date(r.createTime) > lastCheckTime,
);
for (const review of newReviews) {
// Match to customer if possible
const customer = await matchReviewToCustomer(review);
if (customer) {
await updateContact(customer.id, {
left_review: true,
review_platform: "google",
review_rating: review.starRating,
review_date: review.createTime,
});
// Remove from review request sequence
await removeFromSequence(customer.id, "review_request");
}
// Respond to review if negative
if (review.starRating <= 3) {
await alertManager(review);
}
}
};
Step 5: Referral Request
Referral Ask Sequence:
const referralSequence = {
timing: "day_7_to_14", // After review request
condition: "satisfied_customer",
sms: {
message: `{{firstName}}, since you had a great experience with us, do you know anyone else who could use our services? We'd love to help them too!`,
},
email: {
subject: `Know someone who needs {{serviceType}}?`,
body: `Hi {{firstName}},
We loved working with you on {{projectDescription}}!
If you know anyone else who could use our help, we'd really appreciate the referral. As a thank you, we offer:
🎁 {{referralIncentive}}
Just reply with their name and number, or forward them this email.
Thanks for thinking of us!
{{senderName}}`,
},
};
// Referral incentive options
const referralIncentives = {
discount: "$50 off your next service",
giftCard: "$25 Amazon gift card",
donation: "We'll donate $25 to your favorite charity",
service: "Free inspection/consultation",
};
Process Referral Response:
const processReferralResponse = async (fromContactId, message) => {
// Try to extract referral info
const referralInfo = await extractReferralInfo(message);
if (referralInfo.name || referralInfo.phone) {
// Create new lead
const newLead = await createContact({
firstName: referralInfo.name?.split(" ")[0],
lastName: referralInfo.name?.split(" ").slice(1).join(" "),
phone: referralInfo.phone,
email: referralInfo.email,
source: "referral",
referredBy: fromContactId,
tags: ["referral_lead"],
});
// Thank the referrer
await sendSMS(
fromContactId,
`Thanks so much for the referral! We'll take great care of them. Don't forget - you get {{referralIncentive}} when they become a customer!`,
);
// Reach out to the referral
await triggerWorkflow("referral_outreach", newLead.id);
// Track for referral credit
await updateContact(fromContactId, {
referrals_given: (contact.referrals_given || 0) + 1,
pending_referral_credit: true,
});
} else {
// Couldn't extract info - ask for clarification
await sendSMS(
fromContactId,
`Thanks! Could you send me their name and phone number so I can reach out?`,
);
}
};
// Extract referral info using AI
const extractReferralInfo = async (message) => {
const response = await openai.chat.completions.create({
model: "gpt-4o",
messages: [
{
role: "system",
content:
"Extract referral information from this message. Return JSON with: name, phone, email, relationship. Return null for missing fields.",
},
{
role: "user",
content: message,
},
],
response_format: { type: "json_object" },
});
return JSON.parse(response.choices[0].message.content);
};
Step 6: Re-engagement Campaigns
Seasonal Re-engagement:
const seasonalCampaigns = {
spring: {
months: [3, 4, 5],
services: ["HVAC tune-up", "landscaping", "pest control"],
message: `Hey {{firstName}}! Spring is here - time for {{seasonalService}}. As a past customer, you get {{discount}}. Want to schedule?`,
},
summer: {
months: [6, 7, 8],
services: ["AC maintenance", "pool service", "roofing inspection"],
message: `{{firstName}}, summer's heating up! Time for {{seasonalService}}. Book this week and get {{discount}}.`,
},
fall: {
months: [9, 10, 11],
services: ["furnace check", "gutter cleaning", "winterization"],
message: `Hey {{firstName}}, getting ready for winter? Schedule your {{seasonalService}} now before the rush!`,
},
winter: {
months: [12, 1, 2],
services: ["heating repair", "insulation", "snow removal"],
message: `{{firstName}}, staying warm? Let us know if you need any {{seasonalService}} this winter!`,
},
};
// Run seasonal campaigns
const runSeasonalCampaign = async () => {
const currentMonth = new Date().getMonth() + 1;
const season = Object.entries(seasonalCampaigns).find(([_, config]) =>
config.months.includes(currentMonth),
);
if (!season) return;
const [seasonName, config] = season;
// Find past customers who used related services
const eligibleCustomers = await findCustomers({
status: "customer",
serviceType: { $in: config.services },
lastContact: { $lt: daysAgo(90) }, // Haven't heard from us in 90 days
notInCampaign: "seasonal_reengagement",
});
for (const customer of eligibleCustomers) {
await addToCampaign(customer.id, "seasonal_reengagement", {
season: seasonName,
service: customer.serviceType,
});
}
};
Anniversary Re-engagement:
const anniversaryReengagement = async () => {
// Find customers whose service was 1 year ago
const anniversaryCustomers = await findCustomers({
serviceDate: daysAgo(365, 7), // 1 year ago, +/- 7 days
});
for (const customer of anniversaryCustomers) {
await sendSMS(
customer.phone,
`Hey {{firstName}}! It's been a year since we {{serviceType}} for you. Time for an annual checkup? Reply YES and I'll get you on the schedule.`,
);
}
};
Negative Review Recovery
const recoveryWorkflow = {
trigger: "satisfaction_score_low",
steps: [
{
timing: "immediate",
action: "alert_manager",
message: `🚨 Unhappy customer alert: {{firstName}} rated us {{score}}/5 for {{serviceType}}. Contact: {{phone}}`,
},
{
timing: "immediate",
action: "send_customer",
channel: "sms",
message: `{{firstName}}, we're really sorry to hear you weren't satisfied. Our manager {{managerName}} will call you within the hour to make this right.`,
},
{
timing: "1_hour",
action: "manager_call_reminder",
message: `Reminder: Call {{firstName}} at {{phone}} about their service issue.`,
},
{
timing: "24_hours",
condition: "issue_not_resolved",
action: "escalate",
message: `{{firstName}}'s issue hasn't been resolved. Escalating to {{ownerName}}.`,
},
],
};
Metrics to Track
| Metric | Target | How to Improve |
|---|---|---|
| Satisfaction Response Rate | > 50% | Better timing, incentives |
| Review Conversion | > 20% | Simpler ask, direct links |
| Average Rating | > 4.5 | Service quality + recovery |
| Referral Rate | > 15% | Better incentives, right timing |
| Repeat Customer Rate | > 30% | Stay in touch, add value |
Ready to grow your reviews and referrals? Get the implementation package or let us set this up for you.
Get the Complete Implementation Package
Includes n8n workflow templates, TypeScript integrations, message templates, and step-by-step setup guides. Everything you need to deploy this system.
Request AccessRelated Guides
Trade Show & Event Lead Processor - Complete Implementation Guide
Process event leads instantly with personalized AI outreach while the interaction is fresh. Import business cards, scan badges, and follow up same-day.
Multi-Channel Lead Aggregator - Complete Implementation Guide
Consolidate leads from all sources - website, ads, directories, social media - into one unified system with consistent AI-powered initial contact.
Missed Call Text-Back System - Complete Implementation Guide
Never lose a lead to a missed call again. AI instantly texts callers, qualifies their needs, and books appointments automatically.
Ready to Transform Your Lead Generation?
Let's discuss how we can implement this system for your business with expert optimization.
Book Strategy Call