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 (no race conditions)
- ✅ Automatic exposure tracking when links are detected
- ✅ Transparency labels (
[Ad]added automatically) - ✅ “Why this ad?” tooltips on hover
- ✅ Fallback recommendations if no links detected
- ✅ Zero duplicate API calls
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 (citation or product format)
- Links found → Adds
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
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 Citation & 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:"citation"or"product"(format for fallback recommendations)
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 (citation 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)
Reference Implementation: This example is based on the Perplexica integration. See:
perplexica-backend/src/routes/chat.ts- Backend streaming implementationperplexica/src/components/ChatWindow.tsx- Event dispatchingperplexica/src/components/MessageBox.tsx- WeaveAdFormatContainer usage
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
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