Most “AI chatbot” plugins for WordPress are glorified FAQ search bars. A genuinely useful chatbot needs to understand your specific products, policies, and business context. This requires RAG (Retrieval-Augmented Generation) — grounding the AI in your actual content before it generates a response.
Architecture Overview
Customer Message
→ Embed query (vector)
→ Search knowledge base (similarity)
→ Retrieve relevant context (products, policies, FAQ)
→ Send to Claude with context
→ Return answer
→ Log conversation
The key insight: the AI doesn’t memorize your product catalog. For every customer question, it searches your content, finds the relevant pieces, and generates a response based on what it found.
Step 1: Build Your Knowledge Base
Your chatbot is only as good as the content it can search. Extract and structure:
Product data (from WooCommerce):
async function extractProductKnowledge() {
const products = await wooApi.get('products', { per_page: 100 });
return products.data.map(p => ({
type: 'product',
title: p.name,
content: ${p.name}. ${stripHtml(p.description)}. Price: $${p.price}. ${p.stock_status === 'instock' ? 'In stock' : 'Out of stock'}. Categories: ${p.categories.map(c => c.name).join(', ')}.,
metadata: { id: p.id, sku: p.sku, url: p.permalink }
}));
}
Policies (shipping, returns, FAQ pages):
async function extractPolicyPages() {
const pageIds = [123, 456, 789]; // Shipping, Returns, FAQ page IDs
const pages = await Promise.all(
pageIds.map(id => wpApi.get(pages/${id}))
);
return pages.map(p => ({
type: 'policy',
title: p.data.title.rendered,
content: stripHtml(p.data.content.rendered),
metadata: { id: p.data.id, url: p.data.link }
}));
}
Step 2: Create Vector Embeddings
Convert your knowledge base into vector embeddings for semantic search:
const { PineconeClient } = require('@pinecone-database/pinecone');
async function indexKnowledge(documents) {
const pinecone = new PineconeClient();
await pinecone.init({ apiKey: process.env.PINECONE_API_KEY });
const index = pinecone.Index('wordpress-chatbot');
for (const doc of documents) {
// Generate embedding via OpenAI or Voyage AI
const embedding = await generateEmbedding(doc.content);
await index.upsert([{
id: ${doc.type}-${doc.metadata.id},
values: embedding,
metadata: {
type: doc.type,
title: doc.title,
content: doc.content.substring(0, 1000),
url: doc.metadata.url
}
}]);
}
}
Step 3: The Chat Endpoint
app.post('/api/chat', async (req, res) => {,const { message, session_id } = req.body;
// 1. Search knowledge base
const queryEmbedding = await generateEmbedding(message);
const searchResults = await pineconeIndex.query({
vector: queryEmbedding,
topK: 5,
includeMetadata: true
});
// 2. Build context from results
const context = searchResults.matches
.map(m =>
[${m.metadata.type}] ${m.metadata.title}: ${m.metadata.content}).join('\n\n');
// 3. Get conversation history
const history = await getConversationHistory(session_id);
// 4. Generate response with Claude
const response = await anthropic.messages.create({
model: 'claude-sonnet-4-20250514',
max_tokens: 500,
system:
You are a helpful customer service agent for [Store Name].Answer questions using ONLY the provided context. If the context doesn't contain
the answer, say you'll connect them with a human agent.
Never make up product details, prices, or policies.
Be concise and friendly.
Context:
${context}
messages: [
...history,
{ role: 'user', content: message }
]
});
const answer = response.content[0].text;
// 5. Save to conversation history
await saveMessage(session_id, 'user', message);
await saveMessage(session_id, 'assistant', answer);
res.json({ answer, session_id });
});
Step 4: The Frontend Widget
A simple chat widget embedded via WordPress shortcode or plugin:
class ChatWidget {
constructor(container, apiUrl) {
this.container = container;
this.apiUrl = apiUrl;
this.sessionId = this.getSessionId();
this.render();
}
getSessionId() {
let id = sessionStorage.getItem('chat_session');
if (!id) {
id = crypto.randomUUID();
sessionStorage.setItem('chat_session', id);
}
return id;
}
async sendMessage(message) {
this.addMessage('user', message);
this.showTyping();
const response = await fetch(this.apiUrl, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
message,
session_id: this.sessionId
})
});
const data = await response.json();
this.hideTyping();
this.addMessage('assistant', data.answer);
}
}
Handling Edge Cases
Product availability questions:
The chatbot checks real-time stock via the WooCommerce API rather than relying on cached knowledge base data.
Price inquiries:
Always pull current prices from WooCommerce. Cached prices in the vector DB may be stale.
Order status:
Require authentication before showing order details. Never expose order information based on email alone.
Human handoff:
When the AI can’t help or the customer is frustrated, escalate:
const HANDOFF_TRIGGERS = [
'speak to a human', 'real person', 'manager',
'this is not helpful', 'complaint'
];
if (HANDOFF_TRIGGERS.some(t => message.toLowerCase().includes(t))) {
return { answer: "I'll connect you with our team right away.", handoff: true };
}
Measuring Success
Track these metrics:
| Metric | Target |
|---|---|
| Resolution rate (no human needed) | > 60% |
| Average response time | < 3 seconds |
| Customer satisfaction (thumbs up/down) | > 80% positive |
| Hallucination rate (incorrect info) | < 2% |
| Handoff rate | < 30% |
Cost Considerations
| Component | Monthly Cost (1,000 conversations) |
|---|---|
| Claude API | $15-30 |
| Pinecone (Starter) | $0 (free tier) |
| Embedding API | $2-5 |
| Hosting (API server) | $10-20 |
| Total | ~$30-55/month |
Compare this to a human agent handling 1,000 conversations: $2,000-4,000/month.
Conclusion
A RAG-powered chatbot grounded in your actual WordPress/WooCommerce content delivers genuine value — real answers about real products based on real policies. The technical stack (vector search + Claude) is mature and affordable. The key is data quality: your chatbot is only as good as the content you feed it. Start with products and FAQ, measure resolution rates, and expand coverage based on the questions it can’t answer.
Last modified: April 3, 2026
United States / English
Slovensko / Slovenčina
Canada / Français
Türkiye / Türkçe