6.9 KiB
6.9 KiB
Plusvibe Thread Extraction Debugging Guide
Quick Start Testing
Open the browser console on Plusvibe and run these commands:
1. Test DOM Analysis
// Analyze the page structure
PlusvibeExtractor.analyzeDOMStructure();
2. Test API Endpoints
// Test which API endpoints work
await PlusvibeExtractor.testAPIEndpoints();
3. Test Thread Extraction
// Try to extract messages
const messages = await PlusvibeExtractor.extractThreadMessages();
console.log('Extracted messages:', messages);
4. Force DOM Extraction
// Skip API and test DOM extraction
const domMessages = PlusvibeExtractor.extractViaDOM();
console.log('DOM messages:', domMessages);
Finding the Right Selectors
Step 1: Identify Message Containers
- Right-click on a message in Plusvibe
- Select "Inspect Element"
- Look for patterns in the HTML structure
- Note the class names, IDs, and data attributes
Common patterns to look for:
- Classes containing:
message,email,thread,conversation - Data attributes:
data-message-id,data-thread-id,data-email - Container elements:
<article>,<section>,<li>,<div>
Step 2: Test Selectors
// Test a specific selector
const elements = document.querySelectorAll('.your-selector-here');
console.log(`Found ${elements.length} elements`);
elements.forEach((el, i) => {
console.log(`Element ${i}:`, {
text: el.textContent.substring(0, 100),
classes: el.className,
hasEmail: el.textContent.includes('@')
});
});
Step 3: Find Thread ID Location
// Search for thread IDs in various places
const locations = [
// URL
window.location.href,
// Data attributes
...[...document.querySelectorAll('[data-id], [data-thread-id], [data-conversation-id]')].map(el => ({
element: el,
id: el.getAttribute('data-id') || el.getAttribute('data-thread-id') || el.getAttribute('data-conversation-id')
})),
// Text content
document.body.innerText.match(/ID:\s*([a-zA-Z0-9\-_]+)/gi)
];
console.log('Thread ID locations:', locations);
API Integration
Testing API Authentication
// Test if your API key works
fetch('https://app.pipl.ai/api/v2/me', {
headers: {
'Authorization': 'Bearer YOUR_API_KEY_HERE',
'Content-Type': 'application/json'
}
}).then(r => r.json()).then(console.log);
Finding the Right Endpoints
Try these common patterns:
/api/v2/threads/{threadId}/api/v2/conversations/{conversationId}/api/v2/messages?thread={threadId}/api/v2/inbox/messages/api/v1/emails
API Response Formats
Look for these common structures:
// Format 1: Direct messages array
{
"messages": [
{
"id": "123",
"from": "sender@email.com",
"content": "Message text",
"timestamp": "2024-01-01T12:00:00Z"
}
]
}
// Format 2: Nested in data
{
"data": {
"messages": [...]
}
}
// Format 3: Thread with messages
{
"thread": {
"id": "thread123",
"messages": [...]
}
}
Advanced DOM Extraction
Visual Proximity Method
This method finds emails and looks for content nearby:
// Find all email addresses on the page
const emailRegex = /[\w.+-]+@[\w.-]+\.\w+/g;
const walker = document.createTreeWalker(
document.body,
NodeFilter.SHOW_TEXT,
null,
false
);
const emailNodes = [];
let node;
while (node = walker.nextNode()) {
if (emailRegex.test(node.textContent)) {
emailNodes.push({
node: node,
parent: node.parentElement,
email: node.textContent.match(emailRegex)[0]
});
}
}
console.log('Email nodes found:', emailNodes);
Pattern-Based Extraction
Test different patterns:
const patterns = {
// Pattern 1: "email wrote:"
wrote: /([\w.+-]+@[\w.-]+\.\w+)\s+wrote:/gi,
// Pattern 2: Timestamp followed by content
timestamp: /(\d{1,2}[\/\-]\d{1,2}[\/\-]\d{4}.*?)\n([\s\S]+?)(?=\d{1,2}[\/\-]\d{1,2}[\/\-]\d{4}|$)/gi,
// Pattern 3: Email in header
header: /From:\s*([\w.+-]+@[\w.-]+\.\w+)/gi
};
Object.entries(patterns).forEach(([name, pattern]) => {
const matches = [...document.body.innerText.matchAll(pattern)];
console.log(`Pattern "${name}" found ${matches.length} matches`);
matches.slice(0, 3).forEach((match, i) => {
console.log(` Match ${i + 1}:`, match[0].substring(0, 100));
});
});
Common Issues and Solutions
Issue 1: No Messages Found
Solution: Check if messages are in an iframe
const iframes = document.querySelectorAll('iframe');
iframes.forEach((iframe, i) => {
try {
const iframeDoc = iframe.contentDocument;
if (iframeDoc && iframeDoc.body.textContent.includes('@')) {
console.log(`Iframe ${i} contains email content`);
// You may need to run extraction inside the iframe
}
} catch (e) {
console.log(`Iframe ${i} is cross-origin`);
}
});
Issue 2: Dynamic Content Loading
Solution: Wait for content to load
// Observer to detect when messages load
const observer = new MutationObserver((mutations) => {
const hasNewEmails = mutations.some(m =>
[...m.addedNodes].some(n =>
n.textContent && n.textContent.includes('@')
)
);
if (hasNewEmails) {
console.log('New email content detected');
// Re-run extraction
PlusvibeExtractor.extractThreadMessages();
}
});
observer.observe(document.body, {
childList: true,
subtree: true
});
Issue 3: Messages in Shadow DOM
Solution: Check for shadow roots
function findShadowRoots(root = document.body) {
const elements = [];
function traverse(node) {
if (node.shadowRoot) {
elements.push(node.shadowRoot);
traverse(node.shadowRoot);
}
for (const child of node.children || []) {
traverse(child);
}
}
traverse(root);
console.log('Found shadow roots:', elements);
return elements;
}
findShadowRoots();
Reporting Issues
When reporting issues, please provide:
-
Console output from:
PlusvibeExtractor.analyzeDOMStructure(); -
Sample HTML of a message element:
// Right-click message → Inspect → Copy → Copy outerHTML -
API test results (if using API):
await PlusvibeExtractor.testAPIEndpoints(); -
Current URL format:
console.log({ href: window.location.href, pathname: window.location.pathname, search: window.location.search, hash: window.location.hash });
This information will help identify the correct selectors and methods for your Plusvibe instance.