Overview
The Weave Ad Format embeds AdMesh links directly into your LLM responses using an event-driven architecture. Your backend weaves recommendations into the response, and the frontend automatically detects them, adds transparency labels, and tracks engagement.What you get
- Event-driven link detection with no race-condition timing
- Automatic exposure tracking when links are detected
- Transparency labels with
[Ad]added automatically - “Why this ad?” tooltips on hover
- Fallback recommendations when no woven links are detected
- Zero duplicate API calls
At a glance
| Attribute | Weave Ad Format |
|---|---|
| Integration style | Backend plus frontend |
| Best for | Links embedded in the LLM response |
| Setup time | 15 to 20 minutes |
| Code complexity | Moderate |
| Tracking | Automatic after detection |
| Fallback logic | Built in |
Best Fit
Use Weave Ad Format when:- Your backend already shapes or streams assistant responses
- You want AdMesh links embedded directly in the response body
- You want fallback recommendations only when woven links are absent
- You prefer a standalone recommendation panel
- You do not want backend recommendation fetching
Implementation Checklist
- Install the frontend and backend SDKs
- Fetch recommendations on the backend before the LLM response is generated
- Pass recommendation context into the LLM
- Wrap assistant output with
WeaveAdFormatContainer - Dispatch streaming lifecycle events so detection runs at the correct time
Common Use Cases
- AI assistants that stream long-form answers
- chat products where sponsored links should appear inside the response itself
- teams that already control backend prompt construction
- products that need a fallback recommendation module only when weaving does not happen
How It Works
The Weave Ad Format uses an event-driven architecture to eliminate race conditions and ensure accurate link detection:The Flow
- Backend Integration → Your backend fetches recommendations using the backend SDK (
admesh-weave-nodeoradmesh-weave-python) and passes them to your LLM - LLM Weaving → Your LLM naturally weaves AdMesh links into the response text
- Streaming Starts → Your chat component dispatches
streamingStartevent with assistant message ID - Response Streams → LLM response chunks stream to frontend (may or may not contain AdMesh links)
- Streaming Completes → Your chat component dispatches
streamingCompleteevent - Link Detection →
WeaveAdFormatContainerwaits for event, then scans for AdMesh links - Conditional Rendering:
- Links found → Adds
[Ad]labels, fires exposure tracking, shows tooltips (no fallback) - No links found → Renders fallback recommendations (tail or product format)
- Links found → Adds
Integration Summary
| Layer | What it does |
|---|---|
| Backend | Fetches recommendations and provides context to the LLM |
| LLM | Weaves AdMesh links into the assistant response |
| Frontend | Detects links, applies labels, tracks exposures, and renders fallback UI |
Why Event-Driven?
Traditional timeout-based detection causes race conditions:- ❌ Timeout expires before streaming completes → false negative (shows fallback when links exist)
- ❌ Multiple detection cycles → duplicate API calls
- ❌ Unpredictable timing → inconsistent behavior
- ✅ Waits for streaming to complete before detecting links
- ✅ Single detection cycle per message
- ✅ Predictable, reliable behavior
- ✅ Zero duplicate API calls
Core Responsibilities
Backend responsibilities
- fetch recommendations from AdMesh
- pass recommendation context into the LLM
- return the assistant response with woven AdMesh links
Frontend responsibilities
- render the streamed assistant response
- detect AdMesh links after streaming completes
- apply
[Ad]labels and tooltips - track exposures and engagement
- render fallback recommendations only when needed
Implementation Order
- Set up the backend SDK and recommendation fetch flow
- Pass recommendations into the LLM prompt or response generation path
- Render assistant output inside
WeaveAdFormatContainer - Dispatch streaming lifecycle events from your chat component
- Confirm woven-link detection and fallback behavior in the UI
Component: WeaveAdFormatContainer
TheWeaveAdFormatContainer component wraps your LLM response content and uses event-driven detection to handle AdMesh links.
Use this component if:
- ✅ You embed AdMesh links directly in LLM responses
- ✅ You want automatic link detection with event-driven timing
- ✅ You want fallback recommendations if no links present
- ✅ You want automatic tracking and transparency labels
- ❌ You want a separate recommendations panel (use Tail & Product Format instead)
Installation
Backend Integration
Your backend is responsible for fetching recommendations and passing them to your LLM. The LLM then weaves these recommendations into the response text.Step 1: Install Backend SDK
Step 2: Fetch Recommendations and Pass to LLM
UseAdMeshClient to fetch recommendations before calling your LLM:
- ✅ Backend fetches recommendations from AdMesh
- ✅ Backend passes recommendations to your LLM as context
- ✅ LLM naturally weaves them into the response as links
- ✅ Response contains AdMesh tracking links (e.g.,
http://localhost:8000/click/r/abc123...)
See the Node.js SDK documentation or Python SDK documentation for complete backend integration details.
Frontend Integration (admesh-ui-sdk)
The frontend integration has three parts:- Wrap your app with
AdMeshProvider - Wrap LLM response content with
WeaveAdFormatContainer - Dispatch streaming events from your chat component
Step 1: Wrap Your App with AdMeshProvider
Step 2: Wrap LLM Response Content with WeaveAdFormatContainer
In your message rendering component (e.g.,MessageBox.tsx):
messageId: The assistant message ID (from backend, not user message ID)query: The user’s query that prompted this responsefallbackFormat:"tail"or"product"(format for fallback recommendations)
followups_container_id: DOM element ID where follow-ups will be renderedonExecuteQuery: Callback when a follow-up is clicked (required for follow-up functionality)isContainerReady: Signal when the follow-up container is ready in DOM
Step 3: Dispatch Streaming Events from Chat Component
In your chat component (e.g.,ChatWindow.tsx), dispatch events during the streaming flow:
What Happens Automatically
Once you’ve completed the integration,WeaveAdFormatContainer automatically:
- Waits for
streamingCompleteevent (no premature detection) - Scans for AdMesh links in the LLM response
- If links found:
- Adds
[Ad]labels next to links - Fires exposure tracking pixels
- Shows “Why this ad?” tooltips on hover
- Does NOT render fallback recommendations
- Adds
- If no links found:
- Renders fallback recommendations (tail or product format)
- Makes single API call to fetch recommendations
Best Practices
✅ DO:- Dispatch
streamingStartevent when you receive assistant message ID from backend - Dispatch
streamingCompleteevent when streaming finishes - Use assistant message ID (from backend) in events, not user message ID
- Wrap each assistant message with
WeaveAdFormatContainer - Provide the user’s query in the
queryprop - Keep AdMesh links intact in your LLM response
- Let the SDK handle tracking automatically
- Use user message ID in streaming events (must use assistant message ID)
- Dispatch events before you have the assistant message ID
- Modify or remove AdMesh tracking links
- Manually fire tracking pixels
- Remove
[Ad]labels added by the SDK - Create new sessions for every message
Complete End-to-End Example
This example shows the complete event-driven flow based on the Perplexica reference implementation.Backend
Frontend - Chat Component (ChatWindow.tsx)
Frontend - Message Component (MessageBox.tsx)
Optional Follow-Up Recommendations
AdMesh can inject sponsored follow-up queries into your existing follow-up suggestions UI when usingWeaveAdFormatContainer. Follow-ups work in both scenarios: when AdMesh links are detected in the LLM response AND when fallback recommendations are displayed, as long as the fetched recommendations contain followup_query.
Setting Up Follow-Up Recommendations
If your platform already has a follow-up suggestions section (e.g., “Related Questions”, “Suggested Queries”, or similar), AdMesh can add sponsored follow-ups directly into that existing container. Step 1: Identify your existing follow-up container (or create one if you don’t have one):WeaveAdFormatContainer:
followup_query, the SDK will automatically inject the sponsored follow-up into your container using React portals. It will appear alongside your existing suggestions, seamlessly integrated into your UI, regardless of whether links were detected or fallback recommendations are shown.
The SDK automatically:
- Detects follow-up queries from recommendations (works for both link-detected and fallback scenarios)
- Renders the sponsored follow-up in your existing container
- Handles engagement tracking when users interact with follow-ups
- Calls your
onExecuteQuerycallback when a user clicks the sponsored follow-up
Complete Example
Here’s how to integrate follow-ups with WeaveAdFormatContainer:Props Reference
| Prop | Type | Required | Description |
|---|---|---|---|
followups_container_id | string | No | DOM element ID where the SDK should render follow-ups. When provided, the SDK uses portal rendering. |
onExecuteQuery | (query: string) => void | Promise<void> | No | Callback invoked when a user clicks a follow-up. Required for follow-up functionality. Typically executes the query to continue the conversation. |
onFollowupDetected | (followupQuery: string, engagementUrl: string, recommendationId: string) => void | No | Optional callback when a sponsored follow-up is detected. Use this for custom integrations if you prefer to handle rendering yourself (advanced use case). |
isContainerReady | boolean | No | Signal indicating if the follow-up container is ready in the DOM. Useful for streaming or delayed rendering scenarios. |
How It Works
-
Detection: When recommendations fetched by
WeaveAdFormatContainerinclude afollowup_query, the SDK detects it automatically. -
Rendering: When
followups_container_idis provided, the SDK injects the sponsored follow-up into your existing container using React portals. The follow-up appears alongside your existing suggestions, matching your platform’s styling. -
Click Handling: When a user clicks a follow-up:
- The SDK automatically fires engagement tracking (
followup_engagement_url) - Your
onExecuteQuerycallback is invoked with the follow-up query - You execute the query to continue the conversation (e.g., via
sendMessage())
- The SDK automatically fires engagement tracking (
Notes
- Follow-ups are displayed if recommendations include
followup_queryfrom the backend, regardless of whether links are detected or fallback is shown. - The SDK handles all engagement tracking automatically—you only need to provide
onExecuteQueryto continue the conversation. - Use
isContainerReadywhen rendering containers conditionally or after streaming completes. - Follow-ups work with recommendations fetched for link detection, not requiring separate API calls.
Troubleshooting
Fallback recommendations showing even when links exist
Fallback recommendations showing even when links exist
Cause: Events are being dispatched with user message ID instead of assistant message ID.Solution:The
messageId in events MUST match the messageId prop in WeaveAdFormatContainer.Links not being detected
Links not being detected
Check:
- Backend is successfully weaving AdMesh links into LLM response
- Links are in the format:
http://localhost:8000/click/r/...orhttps://tracking.useadmesh.com/click/... streamingCompleteevent is being dispatched after streaming finishes- Assistant message ID is being used in events (not user message ID)
Duplicate API calls
Duplicate API calls
Cause: Multiple detection cycles or timeout-based detection still running.Solution:
- Ensure you’re using the latest version of
admesh-ui-sdk(v1.0.7+) - Verify
streamingCompleteevent is dispatched only once per message - Check console logs for multiple “Setting up listener” messages
Events not being received
Events not being received
Check:
streamingStartevent is dispatched when you receive assistant message IDstreamingCompleteevent is dispatched when streaming finishes- Both events use the same
messageId(assistant message ID) - Both events use the same
sessionId - Events are dispatched BEFORE the component unmounts
[Ad] labels not appearing
[Ad] labels not appearing
Check:
- AdMesh links are present in the LLM response
- Links are being detected (check console logs)
- WeaveResponseProcessor is initialized correctly
- No CSS conflicts hiding the labels
Follow-Ups Not Showing
Follow-Ups Not Showing
If you’re using
followups_container_id but follow-ups aren’t appearing:Check:- Container element with the specified ID exists in the DOM
onExecuteQuerycallback is provided (required for follow-up functionality)- Recommendations from backend include
followup_queryfield - Container is ready before SDK tries to render (use
isContainerReadyif rendering is delayed) - Follow-ups work for both link-detected and fallback scenarios
Key Takeaways
✅ Event-Driven Architecture- Eliminates race conditions and duplicate API calls
- Waits for streaming to complete before detecting links
- Predictable, reliable behavior
- Backend: Fetch recommendations with
admesh-weave-nodeand pass to LLM - Frontend: Wrap responses with
WeaveAdFormatContainerand dispatch events
- Events MUST use assistant message ID (from backend)
- NOT user message ID (generated in frontend)
- Must match the
messageIdprop inWeaveAdFormatContainer
- Link detection happens automatically after
streamingCompleteevent - Exposure tracking fires automatically when links detected
- Fallback recommendations render automatically when no links found
- Zero manual tracking required