An Azure Functions-based service for receiving, validating, and processing Webmentions written in F#. This service accepts webmention notifications, validates them, stores them in Azure Table Storage, and generates RSS feeds from the collected mentions.
Live Service: https://webmentions.lqdev.tech/api/inbox
Webmentions are a web standard for notifications between websites. When someone mentions your website on their blog, social media, or any other web platform, a webmention allows your site to be automatically notified about the mention. This enables decentralized social interactions across the web.
- HTTP Endpoint: Accepts webmention requests via POST to
/inbox - Validation: Validates webmentions using the WebmentionFs library
- Storage: Persists validated webmentions in Azure Table Storage
- RSS Generation: Automatically generates RSS feeds from stored webmentions
- Mention Types: Supports different types of mentions (likes, replies, reposts, bookmarks)
The service consists of two main Azure Functions:
- Trigger: HTTP POST requests to
/inbox - Purpose: Receives and validates incoming webmention requests
- Process:
- Validates the webmention request format and source/target URLs
- Verifies that the source URL actually mentions the target URL
- Stores valid webmentions in Azure Table Storage
- Returns appropriate HTTP responses (200 for success, 400 for errors)
- Trigger: Timer-based (runs daily at 3 AM UTC:
0 0 3 * * *) - Purpose: Generates RSS feeds from stored webmentions
- Process:
- Retrieves webmentions from Azure Table Storage
- Builds an RSS feed containing recent mentions
- Saves the RSS feed to Azure Blob Storage
- .NET 10.0 SDK
- Azure Functions Core Tools
- Azure Storage Account (for Table Storage and Blob Storage)
The service requires the following environment variables:
| Variable | Description | Example |
|---|---|---|
AzureWebJobsStorage |
Azure Storage connection string | DefaultEndpointsProtocol=https;AccountName=... |
PERSONAL_WEBSITE_HOSTNAMES |
Comma-separated list of hostnames to accept webmentions for | example.com,www.example.com |
- Azure Storage Account: Used for both Table Storage (webmentions) and Blob Storage (RSS feeds)
- Azure Functions App: Hosts the webmention processing functions
-
Clone the repository:
git clone https://github.com/lqdev/WebmentionService.git cd WebmentionService -
Install dependencies:
dotnet restore
-
Configure local settings: Create a
local.settings.jsonfile:{ "IsEncrypted": false, "Values": { "AzureWebJobsStorage": "UseDevelopmentStorage=true", "FUNCTIONS_WORKER_RUNTIME": "dotnet-isolated", "PERSONAL_WEBSITE_HOSTNAMES": "localhost:3000,127.0.0.1:3000" } } -
Start Azure Storage Emulator (for local development):
azurite --silent --location c:\azurite --debug c:\azurite\debug.log
-
Run the function app:
func start
-
Create Azure Resources:
- Azure Functions App (with .NET 6.0 runtime)
- Azure Storage Account
-
Configure Application Settings in your Azure Functions App:
AzureWebJobsStorage: Your Azure Storage connection stringPERSONAL_WEBSITE_HOSTNAMES: Your website hostnames
-
Deploy using Azure Functions Core Tools:
func azure functionapp publish <your-function-app-name>
Send a POST request to the /inbox endpoint:
curl -X POST https://your-function-app.azurewebsites.net/api/inbox \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "source=https://example.com/post&target=https://yourdomain.com/article"Parameters:
source(required): URL of the page that mentions your contenttarget(required): URL of your content being mentioned
Responses:
200 OK: Webmention processed successfully400 Bad Request: Invalid webmention or validation error
The service generates an RSS feed daily at 3 AM UTC containing all webmentions. The feed is stored in private Azure Blob Storage for security and content control reasons.
To access the feed in your RSS reader, generate a Shared Access Signature (SAS) token URL:
# Generate a SAS token with 3-year expiration and read-only access
$expiry = (Get-Date).AddYears(3).ToString("yyyy-MM-ddTHH:mm:ssZ")
az storage blob generate-sas \
--account-name <your-storage-account> \
--container-name feeds \
--name "webmentions/index.xml" \
--permissions r \
--expiry $expiry \
--https-only \
--full-uri \
--auth-mode keyThis generates a URL like:
https://your-storage-account.blob.core.windows.net/feeds/webmentions/index.xml?se=2029-01-25...&sp=r&...
Add this URL to your RSS reader (NewsBlur, Elfeed, Feedly, etc.) to consume your webmentions.
Why Private?
- Content Control: Webmentions are for notification purposes, not content redistribution
- Security: Prevents spam harvesters from scraping your feed
- Privacy: Keeps mentions private until you decide to publish them
- No Moderation Overhead: You're not publicly resharing potentially problematic content
For more details, see the original blog post.
Webmentions are stored in the webmentions table with the following structure:
| Field | Type | Description |
|---|---|---|
PartitionKey |
string | URL-encoded target URL |
RowKey |
string | URL-encoded source URL |
IsBookmark |
boolean | Whether this is a bookmark mention |
IsLike |
boolean | Whether this is a like mention |
IsReply |
boolean | Whether this is a reply mention |
IsRepost |
boolean | Whether this is a repost mention |
Timestamp |
DateTimeOffset | When the webmention was received |
This service is built on top of several key libraries:
- WebmentionFs (v0.0.7): Core webmention validation and processing
- Microsoft.Azure.Functions.Extensions: Azure Functions dependency injection
- Microsoft.Azure.WebJobs.Extensions.Tables: Azure Table Storage bindings
- Microsoft.Azure.WebJobs.Extensions.Storage: Azure Storage bindings
-
"Webmention already exists" error:
- This occurs when the same source/target pair is submitted multiple times
- The service prevents duplicate webmentions by using the source/target URLs as the primary key
-
Validation errors:
- Ensure the source URL actually contains a link to the target URL
- Check that both URLs are valid and accessible
- Verify that the target hostname is listed in
PERSONAL_WEBSITE_HOSTNAMES
-
Storage connection issues:
- Verify the
AzureWebJobsStorageconnection string is correct - Ensure the storage account has the necessary permissions
- For local development, make sure the Azure Storage Emulator is running
- Verify the
- Check Azure Functions logs in the Azure portal
- Monitor Table Storage for stored webmentions
- Verify RSS feed generation in Blob Storage
Contributions are welcome! Please feel free to submit issues and pull requests.
This project is licensed under the terms specified in the repository.