\n```\n\n**Solution:**\n\nUse a headless browser for verification:\n\n```javascript\nconst puppeteer = require('puppeteer');\n\nasync function verifyWithBrowser(source, target) {\n const browser = await puppeteer.launch();\n const page = await browser.newPage();\n await page.goto(source, { waitUntil: 'networkidle0' });\n\n const html = await page.content();\n await browser.close();\n\n return html.includes(target);\n}\n```\n\n## 4. Async Processing Delays\n\n### Problem: Mentions Take Too Long to Appear\n\n**Symptoms:**\n- Mentions eventually appear but take hours\n- Queue backlog building up\n- Verification timing out\n\n**Check queue processing:**\n\n```javascript\n// Log queue length\nconsole.log('Queue size:', await queue.count());\n\n// Monitor processing time\nqueue.on('completed', (job, result) => {\n console.log(`Job ${job.id} completed in ${job.finishedOn - job.processedOn}ms`);\n});\n```\n\n**Common Issues:**\n\n### Queue Not Processing\n\n```javascript\n// ❌ Wrong: Queue defined but no worker\nconst queue = new Queue('webmentions');\n\n// ✅ Correct: Worker processing jobs\nconst queue = new Queue('webmentions');\nqueue.process(async (job) => {\n await verifyAndStore(job.data);\n});\n```\n\n### Verification Timeouts\n\n```javascript\n// Set reasonable timeouts\nconst response = await fetch(source, {\n timeout: 10000, // 10 second timeout\n headers: {\n 'User-Agent': 'YourSite/1.0 Webmention'\n }\n});\n```\n\n### Rate Limiting\n\nYou're being rate-limited when fetching source pages:\n\n```javascript\n// Add delays between requests\nconst delay = ms => new Promise(resolve => setTimeout(resolve, ms));\n\nasync function processWithDelay(mentions) {\n for (const mention of mentions) {\n await processMention(mention);\n await delay(1000); // Wait 1 second between requests\n }\n}\n```\n\n## 5. Display Issues\n\n### Problem: Mentions Stored But Not Showing\n\n**Symptoms:**\n- Database has mentions\n- They're verified\n- But don't appear on page\n\n**Check:**\n\n### Query Issues\n\n```javascript\n// ❌ Wrong: Querying wrong target\nconst mentions = await db.mentions.find({\n target: 'https://yourdomain.com/post'\n});\n\n// But stored with trailing slash\n// target: 'https://yourdomain.com/post/'\n\n// ✅ Correct: Use LIKE or normalize\nconst mentions = await db.mentions.find({\n target: { $regex: normalizeUrl(pageUrl) }\n});\n```\n\n### Filtering Too Aggressive\n\n```javascript\n// ❌ Wrong: Only showing approved, but nothing is approved\nconst mentions = await db.mentions.find({\n target: pageUrl,\n status: 'approved' // Nothing has this status!\n});\n\n// ✅ Correct: Show verified mentions\nconst mentions = await db.mentions.find({\n target: pageUrl,\n verified: true\n});\n```\n\n### Client-Side Fetching Failed\n\n```javascript\n// Check browser console\nfetch(`/api/mentions?target=${pageUrl}`)\n .then(res => res.json())\n .then(data => {\n console.log('Mentions loaded:', data);\n })\n .catch(error => {\n console.error('Failed to load mentions:', error);\n });\n```\n\n## 6. Microformats Parsing\n\n### Problem: Mentions Show Without Metadata\n\n**Symptoms:**\n- Mentions appear but no author name/photo\n- All mentions look the same\n- Can't distinguish replies from likes\n\n**Debug:**\n\n```javascript\nconst mf2 = require('microformats-parser');\n\nasync function debugParsing(url) {\n const response = await fetch(url);\n const html = await response.text();\n const parsed = mf2.get({ html, baseUrl: url });\n\n console.log('Parsed data:', JSON.stringify(parsed, null, 2));\n}\n```\n\n**Check source page has microformats:**\n\n```html\n\n
\n \n
\n Author Name\n \n
\n \n
...
\n
\n```\n\n## 7. CORS Issues\n\n### Problem: Browser Can't Fetch Mentions\n\n**Symptoms:**\n- Console shows CORS errors\n- Works on server, fails in browser\n- Cross-origin request blocked\n\n**Solution:**\n\nAdd CORS headers to your API:\n\n```javascript\napp.get('/api/mentions', (req, res) => {\n res.header('Access-Control-Allow-Origin', '*');\n res.header('Access-Control-Allow-Methods', 'GET');\n res.json(mentions);\n});\n```\n\nOr use CORS middleware:\n\n```javascript\nconst cors = require('cors');\napp.use('/api/mentions', cors());\n```\n\n## 8. Testing Tools\n\n### Manual Testing\n\n**Webmentions.com** - Our full-featured service for sending and testing:\nhttps://www.webmentions.com/\n\n**Webmention Rocks** - Comprehensive test suite:\nhttps://webmention.rocks/\n\n**Telegraph** - Alternative sending tool:\nhttps://telegraph.p3k.io/\n\n### Automated Testing\n\n```javascript\n// Test your endpoint\nasync function testEndpoint() {\n const response = await fetch('https://yourdomain.com/webmention', {\n method: 'POST',\n headers: { 'Content-Type': 'application/x-www-form-urlencoded' },\n body: new URLSearchParams({\n source: 'https://test.example.com',\n target: 'https://yourdomain.com/post'\n })\n });\n\n console.log('Status:', response.status);\n console.log('Expected: 200 or 202');\n}\n```\n\n## 9. Debugging Checklist\n\nWork through this systematically:\n\n```bash\n# 1. Can endpoint be discovered?\ncurl -s https://yourdomain.com/post | grep webmention\n\n# 2. Does endpoint respond?\ncurl -X POST https://yourdomain.com/webmention \\\n -d \"source=test\" -d \"target=test\"\n\n# 3. Check endpoint logs\ntail -f /var/log/webmention.log\n\n# 4. Test verification\nnode -e \"require('./verify').test('source-url', 'target-url')\"\n\n# 5. Check database\npsql -c \"SELECT * FROM webmentions WHERE target LIKE '%your-post%'\"\n\n# 6. Test display\ncurl https://yourdomain.com/api/mentions?target=your-post\n```\n\n## Common Solutions Summary\n\n| Problem | Quick Fix |\n|---------|-----------|\n| Not receiving | Add `` |\n| 404 errors | Register POST route |\n| Verification fails | Normalize URLs before comparing |\n| Too slow | Process asynchronously |\n| Not displaying | Check database query |\n| No metadata | Add microformats to source |\n| CORS errors | Add CORS headers |\n\n## Still Stuck?\n\n1. **Check the IndieWeb chat**: https://chat.indieweb.org/\n2. **Test at webmention.rocks**: Validates your implementation\n3. **Use Webmentions.com**: Isolate whether issue is receiving or displaying with our hosted service\n4. **Enable debug logging**: Add verbose logging to track the flow\n\nMost Webmention issues are simple configuration problems that can be fixed in minutes once identified!\n"}}]}
Home

/

FAQ

/

Why aren't my Webmentions showing up?

Why aren't my Webmentions showing up?

Common issues preventing Webmentions from working and how to debug and fix them.

Webmentions not appearing can be frustrating, but the issue usually falls into one of a few common categories. This guide will help you debug and fix the problem.

Quick Diagnostic Checklist

Before diving deep, check these basics:

  • Is your Webmention endpoint discoverable?
  • Is the endpoint URL returning 200/202 responses?
  • Does the source page actually link to the target?
  • Are you checking the right target URL (http vs https, trailing slash)?
  • Have you waited long enough for async processing?

1. Endpoint Discovery Issues

Problem: Senders Can't Find Your Endpoint

Symptoms:

  • No Webmentions received at all
  • Works with Telegraph but not automatically
  • Endpoint logs show no incoming requests

Check:

<!-- View source of your page -->
<link rel="webmention" href="https://yourdomain.com/webmention" />

Test endpoint discovery:

# Check HTML
curl -s https://yourdomain.com/your-post | grep webmention

# Check HTTP headers
curl -I https://yourdomain.com/your-post | grep -i link

Common Mistakes:

<!-- ❌ Wrong: Missing closing tag -->
<link rel="webmention" href="...">

<!-- ❌ Wrong: Typo in rel attribute -->
<link rel="web-mention" href="...">

<!-- ❌ Wrong: Relative URL that's incorrect -->
<link rel="webmention" href="/endpoint">

<!-- ✅ Correct: Absolute URL -->
<link rel="webmention" href="https://yourdomain.com/webmention">

Solution:

Ensure the link tag is in the <head> of every page:

<head>
  <link rel="webmention" href="https://yourdomain.com/webmention" />
</head>

2. Endpoint Not Responding

Problem: Endpoint Returns Errors

Symptoms:

  • Senders receive 404, 500, or timeout errors
  • Webmentions work sporadically
  • Endpoint logs show errors

Test your endpoint:

curl -X POST https://yourdomain.com/webmention \
  -d "source=https://test.example.com" \
  -d "target=https://yourdomain.com/post"

Expected response:

HTTP/1.1 202 Accepted

or

HTTP/1.1 200 OK

Common Issues:

404 Not Found

Your endpoint route isn't registered:

// ❌ Wrong: No route handler
app.listen(3000);

// ✅ Correct: Route registered
app.post('/webmention', handler);
app.listen(3000);

405 Method Not Allowed

Endpoint doesn't accept POST:

// ❌ Wrong: Using GET
app.get('/webmention', handler);

// ✅ Correct: Using POST
app.post('/webmention', handler);

500 Internal Server Error

Check your error logs:

app.post('/webmention', async (req, res) => {
  try {
    // Your code
  } catch (error) {
    console.error('Webmention error:', error);
    res.status(500).send('Error');
  }
});

3. Verification Failures

Problem: Mentions Don't Pass Verification

Symptoms:

  • Endpoint receives mentions but doesn't save them
  • Test mentions work but real ones don't
  • Mentions marked as "unverified"

Common Causes:

URL Mismatch

The target URL in the mention doesn't exactly match your page URL:

// Mention sent for:
target: "https://yourdomain.com/post"

// But your page URL is:
actual: "https://yourdomain.com/post/"  // Note trailing slash

Solution:

Normalize URLs before comparison:

function normalizeUrl(url) {
  const parsed = new URL(url);
  // Remove trailing slash
  parsed.pathname = parsed.pathname.replace(/\/$/, '');
  // Always use https if available
  if (parsed.protocol === 'http:') {
    parsed.protocol = 'https:';
  }
  return parsed.href;
}

// Then compare:
if (normalizeUrl(target) === normalizeUrl(yourPageUrl)) {
  // Match!
}

Link Not Found in Source

Your verification is too strict or the source page has issues:

Debug it:

async function debugVerification(source, target) {
  const response = await fetch(source);
  const html = await response.text();

  console.log('Looking for:', target);
  console.log('Page contains:', html.includes(target));

  // Try variants
  const variants = [
    target,
    target.replace('https://', 'http://'),
    target + '/',
    target.replace(/\/$/, '')
  ];

  variants.forEach(variant => {
    if (html.includes(variant)) {
      console.log('Found variant:', variant);
    }
  });
}

JavaScript-Rendered Links

The source page renders links with JavaScript after page load:

<!-- Server-rendered HTML doesn't include the link -->
<div id="content"></div>

<script>
  // Link added by JS
  document.getElementById('content').innerHTML =
    '<a href="target-url">Link</a>';
</script>

Solution:

Use a headless browser for verification:

const puppeteer = require('puppeteer');

async function verifyWithBrowser(source, target) {
  const browser = await puppeteer.launch();
  const page = await browser.newPage();
  await page.goto(source, { waitUntil: 'networkidle0' });

  const html = await page.content();
  await browser.close();

  return html.includes(target);
}

4. Async Processing Delays

Problem: Mentions Take Too Long to Appear

Symptoms:

  • Mentions eventually appear but take hours
  • Queue backlog building up
  • Verification timing out

Check queue processing:

// Log queue length
console.log('Queue size:', await queue.count());

// Monitor processing time
queue.on('completed', (job, result) => {
  console.log(`Job ${job.id} completed in ${job.finishedOn - job.processedOn}ms`);
});

Common Issues:

Queue Not Processing

// ❌ Wrong: Queue defined but no worker
const queue = new Queue('webmentions');

// ✅ Correct: Worker processing jobs
const queue = new Queue('webmentions');
queue.process(async (job) => {
  await verifyAndStore(job.data);
});

Verification Timeouts

// Set reasonable timeouts
const response = await fetch(source, {
  timeout: 10000, // 10 second timeout
  headers: {
    'User-Agent': 'YourSite/1.0 Webmention'
  }
});

Rate Limiting

You're being rate-limited when fetching source pages:

// Add delays between requests
const delay = ms => new Promise(resolve => setTimeout(resolve, ms));

async function processWithDelay(mentions) {
  for (const mention of mentions) {
    await processMention(mention);
    await delay(1000); // Wait 1 second between requests
  }
}

5. Display Issues

Problem: Mentions Stored But Not Showing

Symptoms:

  • Database has mentions
  • They're verified
  • But don't appear on page

Check:

Query Issues

// ❌ Wrong: Querying wrong target
const mentions = await db.mentions.find({
  target: 'https://yourdomain.com/post'
});

// But stored with trailing slash
// target: 'https://yourdomain.com/post/'

// ✅ Correct: Use LIKE or normalize
const mentions = await db.mentions.find({
  target: { $regex: normalizeUrl(pageUrl) }
});

Filtering Too Aggressive

// ❌ Wrong: Only showing approved, but nothing is approved
const mentions = await db.mentions.find({
  target: pageUrl,
  status: 'approved'  // Nothing has this status!
});

// ✅ Correct: Show verified mentions
const mentions = await db.mentions.find({
  target: pageUrl,
  verified: true
});

Client-Side Fetching Failed

// Check browser console
fetch(`/api/mentions?target=${pageUrl}`)
  .then(res => res.json())
  .then(data => {
    console.log('Mentions loaded:', data);
  })
  .catch(error => {
    console.error('Failed to load mentions:', error);
  });

6. Microformats Parsing

Problem: Mentions Show Without Metadata

Symptoms:

  • Mentions appear but no author name/photo
  • All mentions look the same
  • Can't distinguish replies from likes

Debug:

const mf2 = require('microformats-parser');

async function debugParsing(url) {
  const response = await fetch(url);
  const html = await response.text();
  const parsed = mf2.get({ html, baseUrl: url });

  console.log('Parsed data:', JSON.stringify(parsed, null, 2));
}

Check source page has microformats:

<!-- Required: h-entry -->
<article class="h-entry">
  <!-- Required for author info -->
  <div class="p-author h-card">
    <span class="p-name">Author Name</span>
    <img class="u-photo" src="photo.jpg">
  </div>
  <!-- Required for content -->
  <div class="e-content">...</div>
</article>

7. CORS Issues

Problem: Browser Can't Fetch Mentions

Symptoms:

  • Console shows CORS errors
  • Works on server, fails in browser
  • Cross-origin request blocked

Solution:

Add CORS headers to your API:

app.get('/api/mentions', (req, res) => {
  res.header('Access-Control-Allow-Origin', '*');
  res.header('Access-Control-Allow-Methods', 'GET');
  res.json(mentions);
});

Or use CORS middleware:

const cors = require('cors');
app.use('/api/mentions', cors());

8. Testing Tools

Manual Testing

Webmentions.com - Our full-featured service for sending and testing: https://www.webmentions.com/

Webmention Rocks - Comprehensive test suite: https://webmention.rocks/

Telegraph - Alternative sending tool: https://telegraph.p3k.io/

Automated Testing

// Test your endpoint
async function testEndpoint() {
  const response = await fetch('https://yourdomain.com/webmention', {
    method: 'POST',
    headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
    body: new URLSearchParams({
      source: 'https://test.example.com',
      target: 'https://yourdomain.com/post'
    })
  });

  console.log('Status:', response.status);
  console.log('Expected: 200 or 202');
}

9. Debugging Checklist

Work through this systematically:

# 1. Can endpoint be discovered?
curl -s https://yourdomain.com/post | grep webmention

# 2. Does endpoint respond?
curl -X POST https://yourdomain.com/webmention \
  -d "source=test" -d "target=test"

# 3. Check endpoint logs
tail -f /var/log/webmention.log

# 4. Test verification
node -e "require('./verify').test('source-url', 'target-url')"

# 5. Check database
psql -c "SELECT * FROM webmentions WHERE target LIKE '%your-post%'"

# 6. Test display
curl https://yourdomain.com/api/mentions?target=your-post

Common Solutions Summary

ProblemQuick Fix
Not receivingAdd <link rel="webmention">
404 errorsRegister POST route
Verification failsNormalize URLs before comparing
Too slowProcess asynchronously
Not displayingCheck database query
No metadataAdd microformats to source
CORS errorsAdd CORS headers

Still Stuck?

  1. Check the IndieWeb chat: https://chat.indieweb.org/
  2. Test at webmention.rocks: Validates your implementation
  3. Use Webmentions.com: Isolate whether issue is receiving or displaying with our hosted service
  4. Enable debug logging: Add verbose logging to track the flow

Most Webmention issues are simple configuration problems that can be fixed in minutes once identified!

Related FAQs

How do I handle spam Webmentions?

Strategies and techniques for preventing, detecting, and moderating spam Webmentions on your website.

How do I implement Webmentions on my site?

Step-by-step guide to adding Webmention support to your website, from beginner to advanced.

What are microformats and why do they matter for Webmentions?

Learn how microformats add semantic meaning to your content and enable rich Webmention interactions.

By

Commune Software