Smart product recommendations
Updated: Sep 4, 2026
Copy for LLM
A shopper who opens a conversation with “something for dry skin in winter” has not named a product, and no catalog search alone will answer them well. Meta Business Agent can interpret the need, narrow it with one or two questions, check that the candidates are actually purchasable right now, and present the survivors as a carousel the shopper taps rather than a list they have to read. This page covers the agent instruction, the catalog, the connector tool that supplies live price and stock, and the interactive message that renders the result.
The agent handles:
- Interpreting a described need rather than only a product name
- Asking at most one or two narrowing questions before showing anything
- Validating each candidate against live price and availability before it is shown
- Presenting products as a carousel with a selectable button per card
- Refining the set when the shopper pushes back, without starting over
- Declining to recommend when nothing suitable is available, instead of substituting
Who this guide is for
The examples use a personal-care retailer, but the pattern fits any business whose shoppers describe a problem rather than a product. The agent’s value is the translation step: turning a described need into a small set of specific, purchasable items.
| Organization type | What the shopper describes | What the agent recommends |
|---|---|---|
Personal care and cosmetics | A skin or hair concern, a season, a sensitivity | Products by function and formulation, not by brand line |
Books and media | A mood, a genre, a title they already liked | Titles matched to the described taste rather than to bestseller rank |
Home and garden | A room, a light level, a maintenance appetite | Items matched to conditions rather than to style labels |
Gifting and flowers | A recipient, an occasion, a budget | Arrangements suited to the occasion, with the delivery date honored |
This flow differs from a guided purchase of a known item. Nobody has named a product, so the first job is narrowing, and the measure of success is whether the shopper taps a card rather than asking a follow-up question. If the shopper already knows what they want and needs the right variant, see Single item purchase agent. If recommendations feed a basket the shopper assembles over several turns, see Multi-item cart management.
Each step below notes how the API is used in other scenarios, then applies it to the personal-care example.
Prerequisites
Have the following in place before you configure recommendations. The first three come from Meta Business Agent onboarding; the fourth is a Meta product catalog managed in Commerce Manager; the fifth is your own system.
- An onboarded and enabled Meta Business Agent (
rollout.enabled: true) — see End-to-end setup - A valid system user access token (SUAT) or Business Integration System User (BISU) token with the
whatsapp_business_messagingpermission — see Generate an access token - Your WhatsApp Business phone number ID (
{entity_id}) — the phone number the agent is enabled on, not the WhatsApp Business account ID. Find it in WhatsApp Manager under Account tools > Phone numbers - A Meta product catalog linked to the business, populated with the products you want recommended, required by Set up your product catalog
- A publicly accessible HTTPS endpoint that returns current price and availability for a set of product identifiers, required by Define connector tools
Add agent instructions
Agent instructions shape how the agent responds. The
title is a short identifier, description tells the agent when to apply the instruction, and skill contains the instruction text. Titles are limited to lowercase letters, numbers, and hyphens.A recommendation instruction has to do two things well: stop the agent asking endless qualifying questions, and stop it recommending anything it has not verified.
curl -X POST "https://api.facebook.com/{entity_id}/agent_config/skills" \
-H "Authorization: Bearer {ACCESS_TOKEN}" \
-H "Content-Type: application/json" \
-H "X-API-Version: 2.0.0" \
-d '{
"title": "product-recommendations",
"description": "Applied when a shopper describes what they are looking for by need, occasion, concern, or budget rather than naming a specific product.",
"skill": "Ask at most two narrowing questions before showing products, and only ask when the answer would change what you recommend. Never ask a question the shopper has already answered earlier in the conversation. Call get_product_availability before presenting anything, and present only the products it returns as available. Show between two and ten products as a carousel, never as a numbered list in text. Give one short reason per product, tied to what the shopper actually said, rather than restating the product description. When the shopper rejects the set, change one dimension at a time and show a new carousel rather than repeating the previous one. When nothing available fits what they asked for, say so plainly and offer the closest alternative labeled as an alternative. Do not invent product names, prices, or claims about what a product does, and do not compare against competitor products."
}'
The two-question limit is the instruction that most changes shopper experience. An agent left to qualify freely will ask about skin type, budget, fragrance preference, and format before showing anything, by which point the shopper has stopped replying.
Where else this applies. Any agent that selects from a range needs an explicit ceiling on qualifying questions and an explicit prohibition on presenting unverified items. In electronics the narrowing dimension is usually budget against capability; in apparel it is fit and occasion. The structure of the instruction does not change: bound the questions, verify before presenting, and give a reason tied to what the shopper said.
Set up your product catalog
Meta Business Agent draws product information from your Meta product catalog, which you manage in Meta Commerce Manager rather than through this API. Once the catalog is linked to the business, the agent can already see the products in it — there is no catalog call to make from your integration.
What the agent recommends well depends almost entirely on what your catalog fields say. Recommendations are a matching problem, and the catalog is one side of the match.
| Catalog field | Why it matters for recommendations |
|---|---|
name | Matched directly. Names that encode function recommend better than names that encode only a brand line |
description | The main source for need-based matching. Describe what the product is for, not only what it contains |
image_url | The card image in the carousel. A missing or slow image is the most common cause of a carousel that does not render |
price and currency | Shown on the card. Treat the catalog value as the display default and the connector value as authoritative |
availability | Coarse, in stock or out of stock. Use it to keep discontinued lines out, not as a live stock signal |
item_group_id | Groups variants. Without it the agent can recommend three shades of the same product as three separate recommendations |
color, size, material, pattern | Matched directly when the shopper names one |
gender, age_group | Filters that prevent obviously wrong recommendations |
Write descriptions for the question, not for the product page. A description reading “72-hour hydration with hyaluronic acid and squalane” matches a shopper who asks for hyaluronic acid, but not the far more common shopper who asks for “something for skin that gets tight in winter”. A description that says both matches both.
Two catalog habits cause most bad recommendation sets. Products without
item_group_id produce carousels of near-duplicates. Products whose entire description is a marketing tagline produce recommendations that ignore what the shopper asked, because there was nothing in the text to match against.Where else this applies. Catalog quality sets the ceiling on recommendation quality for every use case, and no agent instruction compensates for a catalog whose descriptions do not describe. Before tuning prompts, read ten of your own product descriptions and ask whether a person who had only those could answer the questions your shoppers actually ask.
Create a product connector
A connector is the bridge to the system that knows current price and stock. The catalog tells the agent what exists; the connector tells it what is purchasable right now.
Supported
auth_type values are API_KEY, OAUTH2_CLIENT_CREDENTIALS, and NONE.curl -X POST "https://api.facebook.com/{entity_id}/agent_connectors" \
-H "Authorization: Bearer {ACCESS_TOKEN}" \
-H "Content-Type: application/json" \
-H "X-API-Version: 2.0.0" \
-d '{
"name": "thornbury_product_api",
"description": "Returns current price, availability, and variant information for Thornbury Botanics products by SKU.",
"base_url": "https://api.thornburybotanics.com/retail/v1",
"auth_type": "API_KEY",
"auth_config": {
"api_key": {
"headers": [
{
"field_name": "X-API-Key",
"value": "{YOUR_PRODUCT_API_KEY}"
}
]
}
}
}'
Save the
id from the response — the tools in Define connector tools are created under it, where it becomes the {connector_id} path parameter.Where else this applies. Recommendation connectors are read-only, which makes them the safest connector to add first and a good place to prove out your authentication and latency before you add anything that writes. If your pricing and your inventory live in different systems, prefer one connector per system so their health is reported separately.
Define connector tools
Connector tools define the operations the agent can invoke. Each tool needs a
name, a description, user_auth_required, and a request_definition describing the outbound HTTP call. Inside request_definition, set method and path, then declare inputs in the section that matches where they belong: path_parameters for {placeholder} segments in the path, query_parameters, headers, or body.Recommendations need one tool. It takes the candidate products the agent is considering and returns which of them can actually be sold, at what price.
Validate candidate products
curl -X POST "https://api.facebook.com/{entity_id}/agent_connectors/{connector_id}/tools" \
-H "Authorization: Bearer {ACCESS_TOKEN}" \
-H "Content-Type: application/json" \
-H "X-API-Version: 2.0.0" \
-d '{
"name": "get_product_availability",
"description": "Takes a list of product SKUs and returns current price, stock status, and image URL for each one that can be sold today. Call this immediately before showing any product to a shopper, in the same turn. Products missing from the response cannot be sold and must not be shown. Never reuse a result from an earlier turn.",
"user_auth_required": false,
"request_definition": {
"method": "POST",
"path": "/products/availability",
"body": {
"content_type": "application/json",
"params": {
"skus": {
"type": "array",
"description": "The candidate product SKUs to validate, taken from the catalog. Send every candidate in one call rather than one call per product.",
"items": "{\"type\": \"string\", \"description\": \"A catalog SKU.\"}"
},
"postcode": {
"type": "string",
"description": "The shopper delivery postcode, when they have given one. Prices and availability can differ by region."
}
},
"required": ["skus"]
}
}
}'
Body fields list their required keys in
body.required. Array fields declare their element type with items, and its value is itself a JSON-encoded object describing the element rather than a bare type name — the bare form is rejected, and this is the part most easily got wrong.Two properties of this tool matter more than its shape. It is batched: the agent sends every candidate in one call, so a carousel costs one round trip rather than ten. And it is exclusive: the response is the whole set of things that may be shown, so a product the tool omits is a product the shopper never sees. Returning a product with a
false stock flag is not equivalent, because it leaves the agent to decide, and it will sometimes decide to show it anyway with a caveat.Return the image URL from this tool even though the catalog also has one. Products whose image has been withdrawn are a common cause of a carousel that silently fails to render, and the system that knows the product is sellable is usually the system that knows its image is live.
Where else this applies. The batch-and-filter shape suits any agent that selects a few items from many: available appointment slots, compatible replacement parts, courses with seats left. The design rule is the same everywhere — have the tool return only what is offerable, rather than returning everything with a flag and trusting the agent to filter.
Add a recommendation carousel
An interactive message lets the agent reply with a rich message instead of plain text. Recommendations use a carousel: a horizontally scrollable set of cards, each with an image, a caption, and a button.
Create interactive messages by posting to
{entity_id}/agent-ui-skills with a title, a component_type, a status, and an instruction describing when to send the component and what to put in it.curl -X POST "https://api.facebook.com/{entity_id}/agent-ui-skills" \
-H "Authorization: Bearer {ACCESS_TOKEN}" \
-H "Content-Type: application/json" \
-H "X-API-Version: 2.0.0" \
-d '{
"title": "product-recommendation-carousel",
"component_type": "carousel_quick_reply",
"status": "enabled",
"instruction": "Send this whenever you are presenting recommended products, including the first set and every refined set after it. Add one card per product returned by get_product_availability, up to ten, and never add a card for a product that tool did not return. Use the product image URL from get_product_availability as the card image. Write the card text as the product name, then the price, then a short reason it suits what the shopper asked for. Label every button Choose this. Set the body text to a single sentence describing what the set has in common, such as the concern it addresses."
}'
Choose the carousel variant that matches what should happen on tap:
component_type | Button behavior | Use when |
|---|---|---|
carousel_quick_reply | Sends a reply back into the conversation | The shopper continues in chat, to pick a variant, add to a basket, or ask a question |
carousel_url | Opens a URL | The shopper leaves for your site to complete the purchase |
Use
carousel_quick_reply for recommendations that continue in the conversation. A carousel_url card ends the conversation at the moment the shopper showed most interest, which is rarely what you want mid-recommendation.Manage existing interactive messages with the following calls:
| To do this | Call |
|---|---|
List interactive messages | GET /{entity_id}/agent-ui-skills |
Retrieve one interactive message | GET /{entity_id}/agent-ui-skills/{instruction_id} |
Update an interactive message | PUT /{entity_id}/agent-ui-skills/{instruction_id} |
Remove an interactive message | DELETE /{entity_id}/agent-ui-skills/{instruction_id} |
Setting
status to disabled turns a component off without deleting it, which is the safer way to test whether a carousel is causing a rendering problem.Carousels take between 2 and 10 cards, card text is limited to 160 characters, and button labels to 20. For the full set of data elements each component type accepts, see Writing interactive messages.
Where else this applies. Carousels suit any set of two to ten comparable options with a picture: products, properties, vehicles, appointment slots with a venue image. Below two options a carousel is heavier than a sentence, and above ten the shopper stops scrolling. When your set is regularly larger than ten, narrow it with a question rather than paginating.
Test the agent
Use Agent test to simulate shopper conversations before going live. Pass
conversation_id from a previous response to continue a multi-turn exchange.curl -X POST "https://api.facebook.com/{entity_id}/agent_test" \
-H "Authorization: Bearer {ACCESS_TOKEN}" \
-H "Content-Type: application/json" \
-H "X-API-Version: 2.0.0" \
-d '{
"user_msg": "I need something for skin that gets really tight in winter"
}'
The response carries
product_variant_ids, listing the products the agent referenced. Assert against that field rather than reading the reply text — it is the reliable way to check which products a given phrasing actually surfaced.Cover these scenarios in your test plan:
| Scenario | Sample message |
|---|---|
Need described, no product named | “Something for skin that gets tight in winter” |
Need plus a constraint | “Something for dry skin, nothing with fragrance” |
Budget-led | “What do you have under 20?” |
Gift, buyer is not the user | “A present for my mother, she has sensitive skin” |
Rejection of the first set | “None of those, I want something lighter” |
Repeated rejection | A second and third rejection in the same conversation |
Nothing suitable available | A constraint your catalog genuinely cannot satisfy |
Named product instead of a need | “Do you have the rosehip serum?” |
Vague opener | “Hi, what do you recommend?” |
Unsupported claim invited | “Will this definitely work for me?” |
The last three deserve automated regressions. A named product is where the agent should answer the question asked rather than opening a recommendation flow, a vague opener is where over-questioning shows up, and an invited claim is where an agent trying to be helpful says something you cannot stand behind.
Where else this applies. Weight a recommendation test plan towards rejection and refinement rather than towards the happy path. First sets are usually reasonable; the failure that costs conversions is the second set that is identical to the first, or that has drifted away from a constraint the shopper stated three turns ago.
Example conversation
This exchange shows the configuration above in use: the agent asks one narrowing question, validates before presenting, refines on one dimension when rejected, and holds an earlier constraint across turns.
Shopper: I need something for skin that gets really tight in winter
Agent: Happy to help. Is that mainly on your face, or hands and body too?
Shopper: Just my face
Agent:(calls
get_product_availability)(sends a carousel of three cards)
These are our richer facial moisturizers, all suited to skin that feels tight in cold weather.
- Bloom Rich Cream — 28.00. The heaviest of the three, for skin that stays tight all day
- Cloudbank Day Balm — 24.00. Lighter texture, sits well under makeup
- Nightfall Repair Mask — 32.00. Overnight, for a few nights when skin is worst
Shopper: None of those, I don’t want anything greasy
Agent:(calls
get_product_availability)(sends a carousel of two cards)
Understood — these two absorb quickly and leave no residue.
- Driftwood Water Cream — 22.00. Water-based, matte finish, leaves no residue
- Meadow Gel Cream — 19.00. Gel texture, absorbs in seconds
Shopper: Is the gel one fragrance-free?
Agent: I can’t confirm that from what I have here, so I don’t want to guess. The full ingredient list is on the product page.
Monitor connector health
The connector logs endpoint,
GET /{entity_id}/agent_connectors/{connector_id}/logs, reports how your product systems are answering the agent. It returns individual error entries by default, or aggregated failure patterns when summary_only is true. Add include_stats=true for success rate and latency.curl -X GET "https://api.facebook.com/{entity_id}/agent_connectors/{connector_id}/logs?summary_only=true&top_n=5&include_stats=true" \
-H "Authorization: Bearer {ACCESS_TOKEN}" \
-H "X-API-Version: 2.0.0"
Logs cover the last seven days, and the requested time range cannot exceed seven days. The response carries two objects:
| Object | Field | What it reports |
|---|---|---|
data | failure_code_name | The failure category |
data | error_message | The message returned by your endpoint |
data | tool_name | Which tool made the call |
data | occurrences | How many times this failure appeared |
stats | success_rate | Share of calls that succeeded |
stats | avg_latency_s | Mean round-trip time in seconds |
stats | p95_latency_s | 95th percentile round-trip time in seconds |
stats | p99_latency_s | 99th percentile round-trip time in seconds |
Filter to one operation with
tool_id when you want a single tool’s health rather than the connector’s overall rate.Watch
p95_latency_s on get_product_availability more closely than its success rate. The tool sits directly between the shopper’s message and the carousel, so its latency is the shopper’s wait, and a validation call that takes several seconds turns a good recommendation into an abandoned conversation.Where else this applies. Read-only tools tend to be monitored casually because their failures look harmless. For recommendations they are not harmless: when validation fails the agent has nothing verified to show, so it either says nothing useful or falls back to describing products in text, and both look to the shopper like an agent that does not know the range.
Tips for this use case
These are the recommendation-specific decisions that most often go wrong once the agent is live.
Cap the qualifying questions. Two is usually right and three is usually too many. Every question before the first carousel is a chance for the shopper to stop replying, and most narrowing that matters can be done after showing something.
Validate in the same turn you present. A stock result from two turns ago is not a stock result. Tie the validation call to the act of presenting, not to the act of searching, or the agent will eventually recommend something it checked several minutes earlier.
Make the tool the filter, not the agent. Return only sellable products rather than everything with an availability flag. Given a flag and a helpful disposition, the agent will sometimes show the unavailable item anyway.
Give one reason per card, tied to their words. “Good for tight winter skin” earns a tap. “Our bestselling moisturizer” does not, because it answers a question the shopper did not ask.
Group variants with
item_group_id. Without it a carousel of five cards can be five shades of one product, which reads as an agent that has not understood the question.Change one dimension per refinement. When a set is rejected, adjust the single attribute the shopper objected to. Rebuilding the whole set loses the constraints they already gave you and usually produces a worse second attempt.
Say when nothing fits. An honest “we don’t have anything fragrance-free in that range” preserves trust. A near-miss presented as a match produces a return and a complaint.
Keep unverifiable product claims out of the agent. Point at the ingredient list and offer a person. This is the single highest-risk thing a recommendation agent can be induced to improvise.
Serve images from somewhere reliable. Carousels fail quietly when an image cannot be fetched, and a silent failure is much harder to diagnose than an error. Use stable, publicly reachable image URLs and check them as part of your catalog hygiene.
Summary checklist
Confirm each of the following before you enable the agent on a production phone number.
- Added a
product-recommendationsagent instruction with an explicit ceiling on qualifying questions - Instructed the agent never to present a product that was not validated in the current turn
- Reviewed catalog descriptions for need-based language rather than only ingredient or feature lists
- Set
item_group_idon every product that has variants - Confirmed every catalog image URL is publicly reachable and stable
- Created a product connector and saved its
connector_id - Defined a batched
get_product_availabilitytool that returns only sellable products - Returned an image URL from the availability tool rather than relying on the catalog copy
- Created a
carousel_quick_replyinteractive message and set itsstatustoenabled - Confirmed carousels stay within 2 to 10 cards, 160-character card text, and 20-character buttons
- Tested vague openers, repeated rejection, budget constraints, and requests you cannot satisfy
- Asserted on
product_variant_idsin agent test rather than on reply text - Set up connector health monitoring with alerting on
get_product_availabilitylatency