\n```\n\n### Step 4: Add CSS\n\n```css\n.webmention {\n display: flex;\n gap: 1rem;\n padding: 1rem;\n border-left: 3px solid #ddd;\n margin: 1rem 0;\n}\n\n.webmention img {\n width: 48px;\n height: 48px;\n border-radius: 50%;\n}\n\n.webmention-content {\n flex: 1;\n}\n\n.webmention-type {\n color: #666;\n font-size: 0.9em;\n}\n\n.webmention-like {\n border-left-color: #e94a4a;\n}\n\n.webmention-repost {\n border-left-color: #4ae290;\n}\n\n.webmention-in-reply-to {\n border-left-color: #4a90e2;\n}\n```\n\nDone! Your static site now receives and displays Webmentions.\n\n## Generator-Specific Implementations\n\n### Jekyll\n\n**Using the Plugin:**\n\n```ruby\n# Gemfile\ngem 'jekyll-webmention_io'\n```\n\n```yaml\n# _config.yml\nwebmentions:\n username: yourdomain.com\n cache_folder: _data\n cache_bad_uris_for: 5\n legacy_domains:\n - http://olddomain.com\n```\n\n```liquid\n\n{% webmentions page.url %}\n```\n\n**Build-Time Fetching:**\n\n```yaml\n# _config.yml\nplugins:\n - jekyll-webmention_io\n\nwebmentions:\n username: yourdomain.com\n```\n\nRun: `jekyll build` (fetches mentions during build)\n\n### Hugo\n\n**Using a Module:**\n\n```bash\n# Install webmention module\nhugo mod get github.com/yourname/hugo-webmentions\n```\n\n```go-html-template\n{{/* layouts/_default/single.html */}}\n{{ $url := .Permalink }}\n{{ $webmentions := getJSON (print \"https://api.webmentions.com/mentions?target=\" $url) }}\n\n{{ with $webmentions.mentions }}\n
\n

Mentions

\n {{ range . }}\n
\n \"{{\n {{ .author.name }}\n {{ .type }}\n {{ with .content.html }}\n

{{ . | safeHTML }}

\n {{ end }}\n
\n {{ end }}\n
\n{{ end }}\n```\n\n**Fetching at Build Time:**\n\n```bash\n# In package.json scripts\n\"build\": \"node fetch-webmentions.js && hugo\"\n```\n\n```javascript\n// fetch-webmentions.js\nconst fs = require('fs');\nconst fetch = require('node-fetch');\n\nasync function fetchMentions() {\n const response = await fetch(\n 'https://api.webmentions.com/mentions?domain=yourdomain.com',\n {\n headers: { Authorization: `Bearer ${process.env.WEBMENTIONS_API_KEY}` }\n }\n );\n const data = await response.json();\n\n fs.writeFileSync(\n 'data/webmentions.json',\n JSON.stringify(data, null, 2)\n );\n}\n\nfetchMentions();\n```\n\n### Eleventy\n\n**Using Our API:**\n\n```javascript\n// .eleventy.js\nmodule.exports = function(eleventyConfig) {\n eleventyConfig.addGlobalData('webmentions', async () => {\n const response = await fetch(\n 'https://api.webmentions.com/mentions?domain=yourdomain.com',\n {\n headers: { Authorization: `Bearer ${process.env.WEBMENTIONS_TOKEN}` }\n }\n );\n return response.json();\n });\n};\n```\n\n```njk\n{# In your post template #}\n{% webmentions page.url %}\n```\n\n**Custom Filter Implementation:**\n\n```javascript\n// .eleventy.js\nconst fetch = require('node-fetch');\n\nmodule.exports = function(eleventyConfig) {\n eleventyConfig.addFilter('webmentionsForUrl', function(webmentions, url) {\n return (webmentions.mentions || []).filter(m => m.target === url);\n });\n};\n```\n\n### Next.js / React\n\n**Webmentions Component:**\n\n```tsx\n// components/Webmentions.tsx\nimport { useEffect, useState } from 'react';\n\ninterface Webmention {\n author: { name: string; photo: string; url: string };\n content?: { text: string; html: string };\n published: string;\n type: string;\n}\n\nexport function Webmentions({ targetUrl }: { targetUrl: string }) {\n const [mentions, setMentions] = useState([]);\n const [loading, setLoading] = useState(true);\n\n useEffect(() => {\n async function fetchMentions() {\n try {\n const apiUrl = `https://api.webmentions.com/mentions?target=${encodeURIComponent(targetUrl)}`;\n const response = await fetch(apiUrl);\n const data = await response.json();\n setMentions(data.mentions || []);\n } catch (error) {\n console.error('Failed to load webmentions:', error);\n } finally {\n setLoading(false);\n }\n }\n\n fetchMentions();\n }, [targetUrl]);\n\n if (loading) return

Loading mentions...

;\n if (mentions.length === 0) return

No mentions yet.

;\n\n return (\n
\n

Mentions

\n {mentions.map((mention, i) => (\n
\n {mention.author?.photo && (\n {mention.author.name}\n )}\n
\n {mention.author?.name || 'Someone'}\n {formatType(mention.type)}\n {mention.content &&

{mention.content.text}

}\n \n
\n
\n ))}\n
\n );\n}\n\nfunction formatType(type: string) {\n const types: Record = {\n 'reply': 'replied',\n 'like': 'liked this',\n 'repost': 'reposted this',\n };\n return types[type] || 'mentioned this';\n}\n```\n\n**Usage:**\n\n```tsx\n// pages/posts/[slug].tsx\nimport { Webmentions } from '@/components/Webmentions';\n\nexport default function Post({ post }: { post: Post }) {\n const url = `https://yourdomain.com/posts/${post.slug}`;\n\n return (\n
\n

{post.title}

\n
\n \n
\n );\n}\n```\n\n**Server-Side Rendering (SSR):**\n\n```tsx\n// pages/posts/[slug].tsx\nexport async function getStaticProps({ params }) {\n const post = await getPost(params.slug);\n const url = `https://yourdomain.com/posts/${params.slug}`;\n\n // Fetch webmentions at build time\n const response = await fetch(\n `https://api.webmentions.com/mentions?target=${encodeURIComponent(url)}`\n );\n const data = await response.json();\n\n return {\n props: {\n post,\n webmentions: data.mentions || [],\n },\n revalidate: 60, // Revalidate every minute\n };\n}\n```\n\n### Gatsby\n\n**Using Our API:**\n\n```javascript\n// gatsby-node.js\nexports.sourceNodes = async ({ actions, createNodeId, createContentDigest }) => {\n const response = await fetch(\n 'https://api.webmentions.com/mentions?domain=yourdomain.com',\n {\n headers: { Authorization: `Bearer ${process.env.WEBMENTIONS_TOKEN}` }\n }\n );\n const data = await response.json();\n\n for (const mention of data.mentions || []) {\n actions.createNode({\n ...mention,\n id: createNodeId(`webmention-${mention.id}`),\n internal: {\n type: 'Webmention',\n contentDigest: createContentDigest(mention),\n },\n });\n }\n};\n```\n\n## Sending Webmentions from Static Sites\n\n### Option 1: GitHub Actions\n\n```yaml\n# .github/workflows/send-webmentions.yml\nname: Send Webmentions\n\non:\n push:\n branches: [main]\n\njobs:\n send:\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v2\n - uses: actions/setup-node@v2\n - run: npm install webmention\n - run: node send-webmentions.js\n```\n\n```javascript\n// send-webmentions.js\nconst { send } = require('webmention');\nconst fs = require('fs');\nconst glob = require('glob');\n\nasync function sendWebmentions() {\n // Find all new/modified posts\n const files = glob.sync('content/posts/**/*.md');\n\n for (const file of files) {\n const content = fs.readFileSync(file, 'utf8');\n const links = extractLinks(content);\n\n for (const link of links) {\n try {\n await send({\n source: `https://yourdomain.com/posts/${getSlug(file)}`,\n target: link,\n });\n console.log(`Sent webmention to ${link}`);\n } catch (error) {\n console.error(`Failed to send to ${link}:`, error);\n }\n }\n }\n}\n\nsendWebmentions();\n```\n\n### Option 2: Netlify Function\n\n```javascript\n// netlify/functions/send-webmentions.js\nconst { send } = require('webmention');\n\nexports.handler = async (event) => {\n const { source, targets } = JSON.parse(event.body);\n\n const results = await Promise.all(\n targets.map(target => send({ source, target }))\n );\n\n return {\n statusCode: 200,\n body: JSON.stringify({ sent: results.length }),\n };\n};\n```\n\n### Option 3: Client-Side Sending\n\n```javascript\n// Send from browser (for testing only)\nasync function sendWebmentionFromBrowser(source, target) {\n // Discover endpoint\n const response = await fetch(target);\n const html = await response.text();\n const match = html.match(/ {\n const url = new URL(event.request.url);\n\n // Cache Webmentions.com API responses\n if (url.hostname === 'api.webmentions.com') {\n event.respondWith(\n caches.open('webmentions-v1').then(cache => {\n return cache.match(event.request).then(response => {\n const fetchPromise = fetch(event.request).then(networkResponse => {\n cache.put(event.request, networkResponse.clone());\n return networkResponse;\n });\n return response || fetchPromise;\n });\n })\n );\n }\n});\n```\n\n### Local Storage Caching\n\n```javascript\nasync function loadWebmentionsWithCache(targetUrl) {\n const cacheKey = `webmentions-${targetUrl}`;\n const cached = localStorage.getItem(cacheKey);\n const cacheTime = localStorage.getItem(`${cacheKey}-time`);\n\n // Use cache if less than 1 hour old\n if (cached && cacheTime && Date.now() - parseInt(cacheTime) < 3600000) {\n displayWebmentions(JSON.parse(cached));\n return;\n }\n\n // Fetch fresh data\n const apiUrl = `https://api.webmentions.com/mentions?target=${encodeURIComponent(targetUrl)}`;\n const response = await fetch(apiUrl);\n const data = await response.json();\n const mentions = data.mentions || [];\n\n // Update cache\n localStorage.setItem(cacheKey, JSON.stringify(mentions));\n localStorage.setItem(`${cacheKey}-time`, Date.now().toString());\n\n displayWebmentions(mentions);\n}\n```\n\n## Performance Tips\n\n1. **Lazy load mentions**: Only fetch when user scrolls to comments section\n2. **Paginate**: Limit initial display, load more on demand\n3. **Cache aggressively**: Mentions don't change frequently\n4. **Build-time fetching**: Bake into static HTML when possible\n5. **Service workers**: Offline access to previously loaded mentions\n\n## Best Practices\n\n- ✅ Add microformats to your content\n- ✅ Set appropriate cache headers\n- ✅ Handle loading and error states\n- ✅ Make mentions responsive\n- ✅ Test with different mention types\n- ✅ Provide fallback for no JavaScript\n- ✅ Use semantic HTML for accessibility\n\nStatic sites with Webmentions get the best of both worlds: blazing fast performance and rich social interactions, all while remaining simple and maintainable.\n"}}]}
Home

/

FAQ

/

How do I add Webmentions to a static site?

How do I add Webmentions to a static site?

Implementing Webmentions on static sites built with Jekyll, Hugo, Eleventy, Next.js, and other generators.

Static sites present unique challenges for Webmentions since they can't run server-side code. However, with hosted services and build-time integration, you can get full Webmention support that's actually simpler than dynamic sites.

The Static Site Strategy

Since your site is static HTML/CSS/JS, you'll use:

  1. Webmentions.com - Hosted endpoint for receiving
  2. JavaScript - Client-side display of mentions
  3. Build-time fetching (optional) - Bake mentions into static HTML
  4. GitHub Actions/Netlify Functions (optional) - Send mentions

Quick Start (Any Static Site)

Step 1: Set Up Webmentions.com

  1. Visit webmentions.com
  2. Create an account and add your domain
  3. Get your endpoint URL

Step 2: Add Endpoints to Your HTML

In your site's <head> (usually in a layout/template):

<!-- Webmention endpoint (required) -->
<link rel="webmention" href="https://receive.webmentions.com/yourdomain.com" />

<!-- Pingback endpoint (optional - captures mentions from legacy WordPress sites) -->
<link rel="pingback" href="https://receive.webmentions.com/xmlrpc/yourdomain.com" />

Replace yourdomain.com with your actual domain. The pingback endpoint is optional but recommended to capture mentions from older blogs.

Step 3: Display Mentions with JavaScript

Add this to your post template:

<div id="webmentions"></div>

<script>
async function loadWebmentions() {
  const targetUrl = window.location.href;
  const apiUrl = `https://api.webmentions.com/mentions?target=${encodeURIComponent(targetUrl)}`;

  try {
    const response = await fetch(apiUrl);
    const data = await response.json();

    displayWebmentions(data.mentions || []);
  } catch (error) {
    console.error('Failed to load webmentions:', error);
  }
}

function displayWebmentions(mentions) {
  const container = document.getElementById('webmentions');

  if (mentions.length === 0) {
    breakpoint-innerHTML = '<p>No mentions yet.</p>';
    return;
  }

  const html = mentions.map(mention => {
    const author = mention.author || {};
    const type = mention['wm-property'] || 'mention';

    return `
      <div class="webmention webmention-${type}">
        ${author.photo ? `<img src="${author.photo}" alt="${author.name || 'Avatar'}">` : ''}
        <div class="webmention-content">
          <strong>${author.name || 'Someone'}</strong>
          <span class="webmention-type">${formatType(type)}</span>
          ${mention.content ? `<p>${mention.content.text || mention.content.html}</p>` : ''}
          <time datetime="${mention.published}">${formatDate(mention.published)}</time>
        </div>
      </div>
    `;
  }).join('');

  breakpoint-innerHTML = `<h3>Mentions</h3>${html}`;
}

function formatType(type) {
  const types = {
    'in-reply-to': 'replied',
    'like-of': 'liked this',
    'repost-of': 'reposted this',
    'bookmark-of': 'bookmarked this',
    'mention-of': 'mentioned this',
  };
  return types[type] || 'mentioned this';
}

function formatDate(dateString) {
  if (!dateString) return '';
  const date = new Date(dateString);
  return date.toLocaleDateString();
}

// Load on page load
if (document.readyState === 'loading') {
  document.addEventListener('DOMContentLoaded', loadWebmentions);
} else {
  loadWebmentions();
}
</script>

Step 4: Add CSS

.webmention {
  display: flex;
  gap: 1rem;
  padding: 1rem;
  border-left: 3px solid #ddd;
  margin: 1rem 0;
}

.webmention img {
  width: 48px;
  height: 48px;
  border-radius: 50%;
}

.webmention-content {
  flex: 1;
}

.webmention-type {
  color: #666;
  font-size: 0.9em;
}

.webmention-like {
  border-left-color: #e94a4a;
}

.webmention-repost {
  border-left-color: #4ae290;
}

.webmention-in-reply-to {
  border-left-color: #4a90e2;
}

Done! Your static site now receives and displays Webmentions.

Generator-Specific Implementations

Jekyll

Using the Plugin:

# Gemfile
gem 'jekyll-webmention_io'
# _config.yml
webmentions:
  username: yourdomain.com
  cache_folder: _data
  cache_bad_uris_for: 5
  legacy_domains:
    - http://olddomain.com
<!-- In your post layout -->
{% webmentions page.url %}

Build-Time Fetching:

# _config.yml
plugins:
  - jekyll-webmention_io

webmentions:
  username: yourdomain.com

Run: jekyll build (fetches mentions during build)

Hugo

Using a Module:

# Install webmention module
hugo mod get github.com/yourname/hugo-webmentions
{{/* layouts/_default/single.html */}}
{{ $url := .Permalink }}
{{ $webmentions := getJSON (print "https://api.webmentions.com/mentions?target=" $url) }}

{{ with $webmentions.mentions }}
  <section class="webmentions">
    <h3>Mentions</h3>
    {{ range . }}
      <div class="webmention">
        <img src="{{ .author.photo }}" alt="{{ .author.name }}">
        <strong>{{ .author.name }}</strong>
        <span>{{ .type }}</span>
        {{ with .content.html }}
          <p>{{ . | safeHTML }}</p>
        {{ end }}
      </div>
    {{ end }}
  </section>
{{ end }}

Fetching at Build Time:

# In package.json scripts
"build": "node fetch-webmentions.js && hugo"
// fetch-webmentions.js
const fs = require('fs');
const fetch = require('node-fetch');

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

  fs.writeFileSync(
    'data/webmentions.json',
    JSON.stringify(data, null, 2)
  );
}

fetchMentions();

Eleventy

Using Our API:

// .eleventy.js
module.exports = function(eleventyConfig) {
  eleventyConfig.addGlobalData('webmentions', async () => {
    const response = await fetch(
      'https://api.webmentions.com/mentions?domain=yourdomain.com',
      {
        headers: { Authorization: `Bearer ${process.env.WEBMENTIONS_TOKEN}` }
      }
    );
    return response.json();
  });
};
{# In your post template #}
{% webmentions page.url %}

Custom Filter Implementation:

// .eleventy.js
const fetch = require('node-fetch');

module.exports = function(eleventyConfig) {
  eleventyConfig.addFilter('webmentionsForUrl', function(webmentions, url) {
    return (webmentions.mentions || []).filter(m => m.target === url);
  });
};

Next.js / React

Webmentions Component:

// components/Webmentions.tsx
import { useEffect, useState } from 'react';

interface Webmention {
  author: { name: string; photo: string; url: string };
  content?: { text: string; html: string };
  published: string;
  type: string;
}

export function Webmentions({ targetUrl }: { targetUrl: string }) {
  const [mentions, setMentions] = useState<Webmention[]>([]);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    async function fetchMentions() {
      try {
        const apiUrl = `https://api.webmentions.com/mentions?target=${encodeURIComponent(targetUrl)}`;
        const response = await fetch(apiUrl);
        const data = await response.json();
        setMentions(data.mentions || []);
      } catch (error) {
        console.error('Failed to load webmentions:', error);
      } finally {
        setLoading(false);
      }
    }

    fetchMentions();
  }, [targetUrl]);

  if (loading) return <p>Loading mentions...</p>;
  if (mentions.length === 0) return <p>No mentions yet.</p>;

  return (
    <section className="webmentions">
      <h3>Mentions</h3>
      {mentions.map((mention, i) => (
        <div key={i} className={`webmention webmention-${mention.type}`}>
          {mention.author?.photo && (
            <img src={mention.author.photo} alt={mention.author.name} />
          )}
          <div>
            <strong>{mention.author?.name || 'Someone'}</strong>
            <span> {formatType(mention.type)}</span>
            {mention.content && <p>{mention.content.text}</p>}
            <time>{new Date(mention.published).toLocaleDateString()}</time>
          </div>
        </div>
      ))}
    </section>
  );
}

function formatType(type: string) {
  const types: Record<string, string> = {
    'reply': 'replied',
    'like': 'liked this',
    'repost': 'reposted this',
  };
  return types[type] || 'mentioned this';
}

Usage:

// pages/posts/[slug].tsx
import { Webmentions } from '@/components/Webmentions';

export default function Post({ post }: { post: Post }) {
  const url = `https://yourdomain.com/posts/${post.slug}`;

  return (
    <article>
      <h1>{post.title}</h1>
      <div dangerouslySetInnerHTML={{ __html: post.content }} />
      <Webmentions targetUrl={url} />
    </article>
  );
}

Server-Side Rendering (SSR):

// pages/posts/[slug].tsx
export async function getStaticProps({ params }) {
  const post = await getPost(params.slug);
  const url = `https://yourdomain.com/posts/${params.slug}`;

  // Fetch webmentions at build time
  const response = await fetch(
    `https://api.webmentions.com/mentions?target=${encodeURIComponent(url)}`
  );
  const data = await response.json();

  return {
    props: {
      post,
      webmentions: data.mentions || [],
    },
    revalidate: 60, // Revalidate every minute
  };
}

Gatsby

Using Our API:

// gatsby-node.js
exports.sourceNodes = async ({ actions, createNodeId, createContentDigest }) => {
  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 || []) {
    actions.createNode({
      ...mention,
      id: createNodeId(`webmention-${mention.id}`),
      internal: {
        type: 'Webmention',
        contentDigest: createContentDigest(mention),
      },
    });
  }
};

Sending Webmentions from Static Sites

Option 1: GitHub Actions

# .github/workflows/send-webmentions.yml
name: Send Webmentions

on:
  push:
    branches: [main]

jobs:
  send:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - uses: actions/setup-node@v2
      - run: npm install webmention
      - run: node send-webmentions.js
// send-webmentions.js
const { send } = require('webmention');
const fs = require('fs');
const glob = require('glob');

async function sendWebmentions() {
  // Find all new/modified posts
  const files = glob.sync('content/posts/**/*.md');

  for (const file of files) {
    const content = fs.readFileSync(file, 'utf8');
    const links = extractLinks(content);

    for (const link of links) {
      try {
        await send({
          source: `https://yourdomain.com/posts/${getSlug(file)}`,
          target: link,
        });
        console.log(`Sent webmention to ${link}`);
      } catch (error) {
        console.error(`Failed to send to ${link}:`, error);
      }
    }
  }
}

sendWebmentions();

Option 2: Netlify Function

// netlify/functions/send-webmentions.js
const { send } = require('webmention');

exports.handler = async (event) => {
  const { source, targets } = JSON.parse(event.body);

  const results = await Promise.all(
    targets.map(target => send({ source, target }))
  );

  return {
    statusCode: 200,
    body: JSON.stringify({ sent: results.length }),
  };
};

Option 3: Client-Side Sending

// Send from browser (for testing only)
async function sendWebmentionFromBrowser(source, target) {
  // Discover endpoint
  const response = await fetch(target);
  const html = await response.text();
  const match = html.match(/<link rel="webmention" href="([^"]+)"/);

  if (!match) {
    console.log('No webmention endpoint found');
    return;
  }

  const endpoint = new URL(match[1], target).href;

  // Send mention
  await fetch(endpoint, {
    method: 'POST',
    headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
    body: new URLSearchParams({ source, target }),
  });
}

Caching Strategies

Service Worker Caching

// sw.js
self.addEventListener('fetch', (event) => {
  const url = new URL(event.request.url);

  // Cache Webmentions.com API responses
  if (url.hostname === 'api.webmentions.com') {
    event.respondWith(
      caches.open('webmentions-v1').then(cache => {
        return cache.match(event.request).then(response => {
          const fetchPromise = fetch(event.request).then(networkResponse => {
            cache.put(event.request, networkResponse.clone());
            return networkResponse;
          });
          return response || fetchPromise;
        });
      })
    );
  }
});

Local Storage Caching

async function loadWebmentionsWithCache(targetUrl) {
  const cacheKey = `webmentions-${targetUrl}`;
  const cached = localStorage.getItem(cacheKey);
  const cacheTime = localStorage.getItem(`${cacheKey}-time`);

  // Use cache if less than 1 hour old
  if (cached && cacheTime && Date.now() - parseInt(cacheTime) < 3600000) {
    displayWebmentions(JSON.parse(cached));
    return;
  }

  // Fetch fresh data
  const apiUrl = `https://api.webmentions.com/mentions?target=${encodeURIComponent(targetUrl)}`;
  const response = await fetch(apiUrl);
  const data = await response.json();
  const mentions = data.mentions || [];

  // Update cache
  localStorage.setItem(cacheKey, JSON.stringify(mentions));
  localStorage.setItem(`${cacheKey}-time`, Date.now().toString());

  displayWebmentions(mentions);
}

Performance Tips

  1. Lazy load mentions: Only fetch when user scrolls to comments section
  2. Paginate: Limit initial display, load more on demand
  3. Cache aggressively: Mentions don't change frequently
  4. Build-time fetching: Bake into static HTML when possible
  5. Service workers: Offline access to previously loaded mentions

Best Practices

  • ✅ Add microformats to your content
  • ✅ Set appropriate cache headers
  • ✅ Handle loading and error states
  • ✅ Make mentions responsive
  • ✅ Test with different mention types
  • ✅ Provide fallback for no JavaScript
  • ✅ Use semantic HTML for accessibility

Static sites with Webmentions get the best of both worlds: blazing fast performance and rich social interactions, all while remaining simple and maintainable.

Related FAQs

How do I implement Webmentions on my site?

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

How do I add Webmentions to WordPress?

Complete guide to implementing Webmentions on WordPress sites using plugins and custom solutions.

How do I handle spam Webmentions?

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

By

Commune Software