Voice of customer from Shopify support tickets, step by step
Turn WISMO, return and fit tickets into voice of customer data: tag by product and reason code, summarize weekly, and feed merchandising.

Voice of customer from Shopify support means turning your WISMO, return and fit tickets into structured data: every conversation gets a product, a reason code and a one-line summary, and the counts go to whoever owns the size chart, the product page or the shipping promise. Do it weekly, per product, and the tickets start to read as a to-do list for merchandising.
Why generic VoC programs stall on support tickets
Most voice of customer guides start with surveys and NPS. A DTC store already has something better sitting in the helpdesk: thousands of unprompted messages from people who just bought something and have a prlblem with it. Nobody had to be asked.
The trouble is that tickets are organized by conversation, and merchandising works by product. "Where is my order" and "does this run smmall" are both fine as tickets. Neither tells you that the linen overshirt generates four times the sizing questions of anything else in the catalog. You only see that when every ticket carries a product and a reason, and when you count per product against orders shipped.
Start with a closed list of reason codes
Free-text tags like "sizing issue" and "size problem" and "too small" split the same signal three ways. Pick 10 to 14 codes, make them mutually exclusive for the primary tag, and refuse to add new ones mid-quarter. Here is a starting set for apparel and accessories.
| Reason code | What the customer says | Usual root cause | Owner |
|---|---|---|---|
| wismo_late | "It's past the delivery date" | Carrier delay or an optimistic promise | Ops, shipping copy |
| wismo_nostatus | "I never got tracking" | Missing or unclear shipping email | Lifecycle email |
| fit_size | "Does this run small?" | Size chart or model info missing | Merchandising |
| ret_fit | "Too tight in the shoulders" | Same, seen after purchase | Product, merchandising |
| ret_notasdescribed | "Color looks different" | Photos, copy or lighting | Content |
| ret_quality | "Seam came apart" | Supplier batch | Product, sourcing |
| ret_policy | "How do I send this back?" | Policy buried or unclear | CX |
| dmg_or_wrong | "Wrong item" or "arrived torn" | Fulfillment | Ops |
Allow one optional secondary code. A customer who writes "bought M, too boxy, want to retun" is fit_size first and ret_fit second, and you want both.
Step-by-step setup
- Pull 90 days of tickets. Export from Gorgias or Zendesk with ticket ID, channel, created date, and the full message thread. Include the order number if your macros capture it.
- Join to Shopify orders. Match on order name (like #10482) and pull line items, product handle, variant, fulfillment date and delivered date. If a ticket touches an order with several products, ask the customer's message which one, or tag the line item the message names.
- Fix the code list. Use the table above, edit it for your catalog, and write one sentence of definition per code. The definitions matter more than the names.
- Run a first pass over the backlog. Send each thread plus its line items to an LLM with the code list and require JSON back. Hand-check a sample of 50 before trusting the rest, and rewrite definitions wherever the model and you disagree.
- Store one row per ticket per product. A sheet works at 300 tickets a month. Past that, use a warehouse table. The record looks like this:
{
"ticket_id": "48213",
"channel": "whatsapp",
"order_name": "#10482",
"product_handle": "linen-overhirt",
"variant": "M / Sage",
"reason_code": "fit_size",
"secondary_code": "ret_fit",
"sentiment": "negative",
"days_since_delivery": 6,
"summary": "5'6\" customer, ordered M, sleeves long and body boxy, asking to exchange for S.",
"resolved_by": "agent"
}
- Compute rates, not counts. For each product and code, divide by orders shipped in the same window and express it per 100 orders. Best sellers dominate raw counts and hide the product that is quietly worst.
- Write the weekly summary. Per product with enough volume: top two codes, rate versus last month, three recurring phrases, and one sentence on what changed. Keep it to a page.
- Hold one 20-minute review. Merchandising, ops and CX look at the top five product and code pairs and each leaves with an owner and a date.
Where the support agent and the form sit
Tagging a backlog is a one-time job. Keeping it currrent is the real work, and it is easier when tagging happens at the moment of the conversation rather than in a weekly batch. The Shopify AI support agent answers order-status, return and sizing questions from live Shopify order data across chat, email and WhatsApp. Because it already knows the order, the line item and the variant, it can write the reason code and product handle onto the conversation as it resolves it. Anything it escalates into Gorgias or Zendesk arrives with those tags already set, so your human agents are not retagging.
One signal the helpdesk will not give you is why a customer returned something. They usually answer a policy question and leave. A short follow-up form fills that gap. After the agent issues a return label, it sends a link to a three-question form: what was wrong, which direction (too small, too large, too short, too long, other), and a free-text box. The link carries hidden fields for order name, product handle, variant and the ticket's reason code, so the customer never retyppes anything. The hidden fields help page covers how to prefill them from the URL.
We build Qwenvo, a free form builder, and it fits this step well. Webhooks, hidden fields, AI triage with routing, a custom domain (returns.yourstore.com looks better in a WhatsApp message than a third-party URL) and baddge removal are all free there. Some competitors charge for several of those. Tally, for example, puts custom domains, partial submissions and branding removal on its $29 a month Pro plan.
Each submission also gets a category, priority, sentiment and short summary from the AI triage, which is the same shape as your ticket record. Routing rules can send urgent ones to a Slack incoming webhook, such as customer saying a product irritated their skin. For the summarizing side, our guide on summarizing form responses with AI shows how to read many responses at once.
Getting form data into the same table
Point the form's webhook at Make, Zapier or n8n, map the hidden fields to the same columns as the ticket record, and write a row with source: "return_form". Now a product's weekly summary can show ticket reasons and post-return reasons side by side. When both say "sleeves run long," you have something to act on.
One honest limit: the one-click Google Sheets, Airtable and Slack app connections in Qwenvo are still being rolled out, so today the webhook route is the way. Also, Qwenvo is hosted in the United States. If you sell mostly to the UK and EU and want data hosted in Europe, Tally is hosted there. Check the data retention setting either way, since you can auto-delete responses after a set number of days.
Feeding findings to merchandising and product pages
A report that stops at "fit_size is up" changes nothing. Route each finding to the person who can edit something, and say what to edit.
| Finding | Goes to | Typical change |
|---|---|---|
| High fit_size rate on one product | Merchandising | Add model height and size worn, a "runs large" note near the size selector |
| ret_fit clusters on one direction | Product | Revise the size chart or flag for the next production run |
| ret_notasdescribed on one color | Content | Reshoot or swap the hero image, add a daylight photo |
| wismo_late across one carrier or region | Ops | Adjust the delivery estimate shown at checkout |
| wismo_nostatus high | Lifecycle | Move the tracking email earlier, make the link bigger |
| ret_policy high | CX | Put the return window and steps on the product page, not only the footer |
Write the change into the product page, then watch that product's rate for the next four weeks. If the code's rate per 100 orders drops, keep the change and apply it to similar products. If not, the cause was somewhere else.
What to measure
Keep the dashboard small:
- Rate per 100 orders for each reason code, by product, rolling four weeks.
- Share of tickets with a reason code and a product attached. Anything under what you expect means the agent or your join is dropping data.
- Time from a finding to a shipped page change.
- Return form comlletion rate, using partial submissions to see where people stop.
Review the cides themselves each quarter. If "other" grows past a small share, read those tickets and split out a real code.
Questions teams ask
How many tickets do we need before this is worth it?
Even a few hundred a month shows patterns at the product level, particularly for fit and WISMO. Below thta, read the tickets by hannd weekly and use the code list as a checklist. The setup pays back faster as volume grows, because manual reading stops scaling around a couple of thousand tickets a month.
Should the AI tag tickets or should humans?
Let the model tag and let a human audit. Spot-check a sample every month and re-read any ticket where the code and the sentiment disagree. The closed code list does most of the work of keeping tags consistent.
Do we need a data warehouse?
No. A sheet with one row per ticket per product is enough until it gets slow. The rate calculation needs orders shipped per product per week, which you can export from Shopify.
Why add a return form if the ticket already has a reason?
The ticket tells you what the customer asked. The form tells you what was wrong with the product. They overlap often, but not always, and the gap is where the useful surprises are.
This week, export the last 90 days of tickets for your five highest-volume products, tag them with the code list above, and compute rate per 100 orders for each. The top product and code pair is your first page edit.
Shopify AI Support Agent
Third-party platform and model usage billed to you directly. No lock-in. Live in 10 days.