Home

/

FAQ

/

What is a Webmention endpoint?

What is a Webmention endpoint?

Understanding what a Webmention endpoint is, how it works, and how to set one up for your website.

A Webmention endpoint is a URL on your website that receives notifications when other sites link to your content. Think of it as a mailbox where the web delivers notifications about who's talking about your posts.

The Basics

When someone mentions your content and sends a Webmention, their system makes an HTTP POST request to your endpoint with two pieces of information:

  • source: The URL of their page that mentions you
  • target: The URL of your page being mentioned

Your endpoint receives this notification, verifies it's legitimate, and processes it however you choose.

How It's Discovered

Other websites need to find your endpoint before they can send you Webmentions. You advertise it in two standard ways:

1. HTML Link Element

Add this to your page's <head>:

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

2. HTTP Link Header

Your server can send this HTTP header:

Link: <https://yourdomain.com/webmention>; rel="webmention"

Most implementations use the HTML method as it's simpler, but supporting both provides maximum compatibility.

What an Endpoint Does

A Webmention endpoint has three main responsibilities:

1. Receive the Notification

Accept POST requests with source and target parameters:

app.post('/webmention', async (req, res) => {
  const { source, target } = req.body;

  // Basic validation
  if (!source || !target) {
    return res.status(400).send('Missing required parameters');
  }

  // Accept the mention
  res.status(202).send('Accepted');
});

The endpoint should return 202 Accepted quickly, then process asynchronously.

2. Verify the Mention

Fetch the source page and confirm it actually links to your target:

async function verifyMention(source, target) {
  // Fetch the source page
  const response = await fetch(source);
  const html = await response.text();

  // Check if target URL appears in the source
  if (!html.includes(target)) {
    throw new Error('Link not found');
  }

  return true;
}

Why verify? Anyone can send a POST request claiming they linked to you. Verification ensures the link actually exists.

3. Process and Store

Once verified, extract metadata and store the mention:

async function processMention(source, target) {
  // Parse microformats for rich data
  const data = await parseMetadata(source);

  // Store in database
  await db.mentions.insert({
    source,
    target,
    author: data.author,
    content: data.content,
    type: data.type, // reply, like, repost, etc.
    verified: true,
    receivedAt: new Date()
  });
}

Endpoint Types

Self-Hosted Endpoint

You run your own endpoint on your server:

Pros:

  • Full control over processing
  • Custom storage and display
  • No third-party dependencies
  • Privacy of mention data

Cons:

  • More complex to implement
  • Server maintenance required
  • Must handle spam/abuse
  • Need database storage

Example (Node.js/Express):

const express = require('express');
const app = express();

app.post('/webmention',
  express.urlencoded({ extended: true }),
  async (req, res) => {
    const { source, target } = req.body;

    // Validate URLs
    if (!isValidUrl(source) || !isValidUrl(target)) {
      return res.status(400).send('Invalid URLs');
    }

    // Check target is on this domain
    if (!target.startsWith('https://yourdomain.com')) {
      return res.status(400).send('Invalid target');
    }

    // Queue for processing
    await queue.add({ source, target });

    // Return 202 immediately
    res.status(202).send('Accepted for processing');
  }
);

Hosted Endpoint (Webmentions.com)

Use our hosted service at webmentions.com to handle receiving:

Pros:

  • Quick setup (5 minutes)
  • Full-featured API
  • Spam filtering built-in
  • Handles verification automatically
  • Dashboard for managing mentions

Cons:

  • Data stored on our servers
  • API rate limits apply

Setup:

<!-- Add to your <head> -->
<link rel="webmention" href="https://receive.webmentions.com/yourdomain.com" />

Replace yourdomain.com with your actual domain. Then fetch mentions via our API:

const response = await fetch(
  'https://api.webmentions.com/mentions?target=https://yourdomain.com/post'
);
const data = await response.json();

Hybrid Approach

Some sites use our hosted endpoint for receiving but process/store mentions themselves:

// Poll Webmentions.com periodically
async function syncMentions() {
  const response = await fetch(
    'https://api.webmentions.com/mentions?domain=yourdomain.com',
    {
      headers: { Authorization: `Bearer ${process.env.WEBMENTIONS_TOKEN}` }
    }
  );
  const data = await response.json();

  for (const mention of data.mentions || []) {
    // Process with your own logic
    await processAndStore(mention);
  }
}

// Run every hour
setInterval(syncMentions, 3600000);

Endpoint URL Patterns

Your endpoint can be:

Global (handles all pages):

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

Per-page (different endpoints for different sections):

<!-- On blog posts -->
<link rel="webmention" href="https://yourdomain.com/webmention/blog" />

<!-- On projects -->
<link rel="webmention" href="https://yourdomain.com/webmention/projects" />

Most sites use a single global endpoint for simplicity.

Security Considerations

Rate Limiting

Prevent abuse by limiting requests:

const rateLimit = require('express-rate-limit');

const limiter = rateLimit({
  windowMs: 15 * 60 * 1000, // 15 minutes
  max: 100, // 100 requests per window
  message: 'Too many requests'
});

app.use('/webmention', limiter);

URL Validation

Ensure source and target are valid, accessible URLs:

function isValidUrl(string) {
  try {
    const url = new URL(string);
    return url.protocol === 'http:' || url.protocol === 'https:';
  } catch {
    return false;
  }
}

function isValidTarget(target, allowedDomain) {
  return target.startsWith(`https://${allowedDomain}`);
}

Prevent SSRF Attacks

Don't allow mentions from private IP ranges:

function isPublicUrl(url) {
  const privateRanges = [
    /^10\./,
    /^172\.(1[6-9]|2[0-9]|3[01])\./,
    /^192\.168\./,
    /^127\./,
    /^localhost$/
  ];

  const hostname = new URL(url).hostname;
  return !privateRanges.some(range => range.test(hostname));
}

Async Processing

Never fetch the source URL synchronously in the request handler:

// ❌ BAD: Synchronous
app.post('/webmention', async (req, res) => {
  await verifyMention(req.body.source, req.body.target); // Blocks!
  res.send('OK');
});

// ✅ GOOD: Asynchronous
app.post('/webmention', async (req, res) => {
  await queue.add(req.body); // Queue it
  res.status(202).send('Accepted'); // Return immediately
});

This prevents attackers from tying up your server with slow requests.

Testing Your Endpoint

Manual Testing with Webmentions.com

The easiest way to test your endpoint is using our Webmentions.com service:

  1. Sign up and add your domain
  2. Use our sending tools to send a test Webmention to your target URL
  3. Verify your endpoint received the notification
  4. Check the dashboard to see the mention processed

Alternative: Telegraph

You can also use Telegraph to send test Webmentions:

  1. Enter your target URL
  2. Enter a source URL (create a test page linking to your target)
  3. Send the Webmention
  4. Check your endpoint received it

Automated Testing with webmention.rocks

Visit webmention.rocks for comprehensive tests:

  • Discovery tests (HTML and HTTP)
  • Verification tests
  • Update and deletion handling
  • Error scenarios

Command Line Testing

Send a test Webmention with curl:

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

Expected response:

HTTP/1.1 202 Accepted

Common Endpoint Patterns

Minimal Endpoint

Just accept and log:

app.post('/webmention', (req, res) => {
  console.log('Received:', req.body);
  res.status(202).send('Accepted');
});

Production Endpoint

Full implementation:

app.post('/webmention', async (req, res) => {
  try {
    // 1. Extract and validate
    const { source, target } = req.body;
    if (!isValidUrl(source) || !isValidTarget(target)) {
      return res.status(400).send('Invalid parameters');
    }

    // 2. Queue for async processing
    await mentionQueue.add({
      source,
      target,
      receivedAt: new Date(),
      ip: req.ip
    });

    // 3. Return 202 immediately
    res.status(202).send('Accepted');

  } catch (error) {
    console.error('Webmention error:', error);
    res.status(500).send('Server error');
  }
});

// Async worker processes queued mentions
mentionQueue.process(async (job) => {
  const { source, target } = job.data;

  // Verify the mention
  const isValid = await verifyMention(source, target);
  if (!isValid) return;

  // Parse metadata
  const data = await parseMetadata(source);

  // Store in database
  await saveMention({ source, target, ...data });
});

Next Steps

Once you have an endpoint running:

  1. Add microformats to your content for richer mentions
  2. Display received mentions on your pages
  3. Implement moderation to handle spam
  4. Send Webmentions when you publish content
  5. Monitor and maintain your endpoint

The endpoint is just the beginning—it's the foundation for building a fully interactive, decentralized web presence.

Learn More

Related FAQs

What are microformats and why do they matter for Webmentions?

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

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.

By

Commune Software