How to Auto-Respond to Google Reviews with AI
Wire a webhook, an LLM, and one POST into a Google review auto-responder — star-rating-aware drafts, human approval for negative reviews, multi-location routing.
The pipeline
Three parts, no Google API integration on your side:
- Webhook in — Postproxy syncs Google Business reviews twice daily and fires
profile_comment.createdfor each new one, with text, reviewer name, location, and star rating. - LLM drafts — a prompt with the review, rating, and your business context produces the reply.
- POST out — one call publishes the reply to Google.
The basics of listing and replying are covered in How to Reply to Google Business Reviews via API; this guide adds the automation layer.
The handler
import Anthropic from "@anthropic-ai/sdk";const anthropic = new Anthropic();
app.post("/webhooks/postproxy", async (req, res) => { res.sendStatus(200);
const event = req.body; if (event.type !== "profile_comment.created") return;
const review = event.data.object; if (review.parent_external_id) return; // skip replies (incl. our own) if (review.status !== "synced") return; // skip our published replies
const stars = review.platform_data?.star_rating; if (stars <= 3) return queueForHuman(review); // negatives get a person
const draft = await anthropic.messages.create({ model: "claude-sonnet-4-6", max_tokens: 300, messages: [{ role: "user", content: `You reply to Google reviews for Fern & Co Coffee, warm and specific, ` + `under 60 words, no emoji, never offer discounts.\n` + `Rating: ${stars} stars\n` + `Reviewer: ${review.author_username}\n` + `Review: ${review.body ?? "(rating only, no text)"}\n` + `Write only the reply text.`, }], });
await fetch( `https://api.postproxy.dev/api/profiles/${PROFILE_ID}/comments`, { method: "POST", headers: { Authorization: `Bearer ${process.env.POSTPROXY_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ parent_id: review.id, body: draft.content[0].text, }), } );});Two filters matter. parent_external_id being set means the record is a reply, not a review. And your own published replies also fire profile_comment.created — they arrive with status other than synced, so the status check stops the bot from answering itself.
Handle Google’s quirks in the prompt
- Star-only reviews —
bodyisnullwhilestar_ratingis set. Pass “(rating only, no text)” so the model thanks the rating instead of hallucinating what the customer said. - Multi-location accounts — the payload’s
placement_idtells you which location the review belongs to. Use it to inject the right business name and voice per location, or to ignore locations you don’t manage. (Webhooks fire for all locations of the account.) - One reply per review — Google supports a single owner reply. Posting again replaces context, so dedupe on
review.id.
Keep a human on negatives
Auto-replying to a 1-star review is how automations make the news. The split that works:
- 4-5 stars → auto-publish.
- 1-3 stars → LLM still drafts, but the draft lands in a queue (Slack message, ticket) and a human edits before the POST. The reply call is identical — it just runs on approval instead of on webhook.
Track outcomes via comment.status: pending → published, or failed with Google’s error in error_details (the profile_comment.failed webhook covers the permanent failures).
Why response rate is worth automating
Google surfaces owner responses prominently, and prospective customers read them as a service signal — an unanswered complaint is the loudest item on the listing. An auto-responder gets a consistent response rate to 100% of positives, while concentrating human time on the reviews where wording actually matters.
If you’d rather hand the whole loop to an agent instead of a webhook handler, the same reply tools are exposed over MCP — see How to Let AI Agents Answer DMs and Comments via MCP.