ContentSignals

Content-Signal headers and markdown content negotiation for AI agents. One middleware call. Three behaviors.

$ npm install contentsignals click to copy
HTTP Response Headers
Content-Signal: search=yes, ai-input=yes, ai-train=no
Content-Type:    text/markdown; charset=utf-8
x-markdown-tokens: 312
Vary:            Accept

What it does

📡 Content-Signal Headers

Adds Content-Signal to every response, telling AI agents what they may do with your content — search, RAG, or training. Based on the Content Signals spec.

🔀 Content Negotiation

When an agent sends Accept: text/markdown, serves the .html.md companion file instead of HTML. Falls back to on-the-fly conversion via Turndown.

🔢 Token Count Header

Adds x-markdown-tokens so agents can budget their context window before downloading. Reads from YAML frontmatter or estimates at ~4 chars/token.

🎯 Per-Path Overrides

Use glob patterns to set different signal values per route. Block AI access to /api/** while allowing /blog/** for search and RAG.

On-the-fly Conversion

No companion file? Set convert: true and HTML responses are converted to markdown automatically. Strip nav, footer, ads with configurable selectors.

🛡️ Security Built-in

Path traversal protection with separator-bounded checks. Vary header merging preserves downstream values. Status codes correctly preserved through interception.

How it works

1

Install

npm install contentsignals

2

Add middleware

app.use(contentsignals({...}))

3

Drop companions

Place .html.md files next to your HTML pages

4

Done

Agents get markdown, browsers get HTML, everyone gets Content-Signal

Quick start

Add to any Express app in 4 lines.

import express from 'express';
import { contentsignals } from 'contentsignals';

const app = express();

app.use(contentsignals({
  signals: { search: true, aiInput: true, aiTrain: false },
  staticDir: './public',
  convert: true,
}));

app.use(express.static('./public'));
app.listen(3000);

Works with any framework

Standard (req, res, next) middleware. Runs everywhere Node.js runs.