The rule, for your team's review
Rule version 0.1, draft of 21 October 2026, prepared by AnswerShare. Nothing here is deployed. Your team reviews, edits, merges and deploys it.
What we propose, and why
We propose a Next.js rewrite rule in next.config.js, in the beforeFiles phase, that sends page requests from named AI crawlers to AnswerShare as an external rewrite. We are not proposing middleware, and the rule does not go in vercel.json.
- Why not
vercel.json. Our 19 October email said the rule would go invercel.json. That was a mistake; the diagram we sent with it shows the correct place,next.config.js. Vercel appliesvercel.jsonrewrites only after it checks for a matching file ("precedence is given to the filesystem prior to rewrites being applied", Vercel's vercel.json documentation). Your pages are prerendered: on 21 October your home page and/es-USboth answered withx-nextjs-prerender: 1. Avercel.jsonrule would therefore be skipped for most of your pages. Next.jsbeforeFilesrewrites are checked before files and pages, so the rule works on prerendered pages. - Why not middleware. A rewrite rule is configuration. Next.js reads
rewrites()once, at build time, and no code of ours runs on any request. Middleware would run on every page request, including your visitors' requests. It would also need a credential in your Vercel environment variables, and it would have to be kept current with Next.js releases. Your 21 October reply said the move to the rewrite rule addressed your biggest concerns, so we kept it. - The trade-off, stated plainly. A rewrite rule has no built-in fallback. If AnswerShare cannot answer, Vercel returns an error to that AI crawler for that request. People and search engines are never affected. The section "If AnswerShare errors or times out" gives each case and what we do about it.
How it decides
- User agent only. The rule reads the request's
User-Agentheader. It never looks at IP addresses or networks. - Named AI crawlers in. A request is routed only if its user agent contains one of the AI crawler names in the list below. The list comes from AnswerShare's canonical crawler classification, the
AI_BOTSset insrc/bot-classification.tsof our shared library (aryah-shared), at commitb43382dof 2 October 2026. Changes reach you only as pull requests. - Search crawlers out, always. The rule refuses any user agent that contains a search crawler's name, even one that also contains an AI name. That list is our
SEARCH_BOTSset from the same file: Googlebot in all its variants, Google-InspectionTool (Search Console's inspection tool), Bingbot, Applebot, DuckDuckBot, YandexBot, Baiduspider and PetalBot. Everyone else, including every person, gets your site untouched. - Pages only. The rule skips Next.js internals (
/_next/),/api/,/_vercel/,/.well-known/and any path ending in a file extension: images, scripts, styles, icons,robots.txt,sitemap.xmlandmanifest.webmanifest. None of the 497 page addresses in your sitemap ends in a file extension, so every page is covered and every asset is excluded. - Not in-app requests or form submissions. The rule also skips any request carrying the
RSCheader (Next.js in-app navigation data) or theNext-Actionheader (Next.js form submissions), and/api/is excluded by path. We found no checkout, cart or account pages on www; the rental portal sign-up page is an ordinary page with a form.Question for HOLT: Does www have any other account, checkout or transaction paths we should exclude from the rule?
- English and Spanish alike. Next.js runs your existing language middleware first and this rule after it, so the rule covers English pages at
/and Spanish pages under/es-US. We test both on the preview.
Matching is case-sensitive, because Next.js header patterns are. Each name matches as written in the list and in lower case, which covers the published user agent of every crawler on the list. A crawler that spells its name with some other capitalisation gets your normal page, which is the safe direction.
What reaches AnswerShare
Only requests that match the rule. Vercel forwards the crawler's request as it arrived: the page path and query, the crawler's user agent and its other request headers, plus Vercel's standard forwarding headers (x-forwarded-for, x-real-ip, x-forwarded-host, x-forwarded-proto), which carry the crawler's IP address. Requests from people and search crawlers never match, so nothing from them reaches us. This is the same description we gave in our answer to your question 13.
Every response we send back is marked Cache-Control: private, no-store. Vercel honours upstream cache headers on external rewrites, so it does not store the AI version, and an AI copy never sits in a cache where a visitor could get it.
If AnswerShare errors or times out
The rule points at an AnswerShare edge service that builds each response. Here is what an AI crawler gets in each case. In every case, people and search crawlers get your normal page, because their requests never reach us.
| Case | What the AI crawler gets |
|---|---|
| Normal | The AI version of the page, status 200. |
| The page has no AI version yet (for example, a page you published minutes ago) | Your normal page. Our edge service fetches it from your site and returns it unchanged. That fetch carries a pass-through header the rule excludes, so it cannot loop back to us. |
| Our content service fails or is slow | Your normal page, the same way, once our time budget runs out [CONFIRM: time budget, proposed 2.5 seconds]. |
| Your site is slow or down when our edge service fetches your page | Status 502 from our edge service, if your page has not arrived within 10 seconds or the fetch fails. |
| Our edge service itself is down or unreachable | An error from Vercel, status 502 (ROUTER_EXTERNAL_TARGET_CONNECTION_ERROR). There is no fallback to your page in this case. |
| Our edge service accepts the connection but never answers | Vercel waits up to its 120-second limit for external rewrites, then returns 502 (ROUTER_EXTERNAL_TARGET_ERROR). |
The last two cases are the cost of having no code on your visitors' requests. A crawler that gets an error retries later. The stop conditions in the plan call for a revert if failures pass 1% of AI-crawler requests in an hour or last 15 minutes.
The fall-back to your normal page in the second and third rows is built and running on our side. On 22 October 2026 we sent GPTBot requests for your home page and for /es-US to our edge service. Each got your own page back with status 200, marked Cache-Control: private, no-store and x-answershare-variant: passthrough, in under 2 seconds. We test it again on your preview (tests T14 and T15).
Blast radius of each failure
For each failure below: what your human layer gets (your visitors, plus Googlebot and the other search crawlers), what our layer gets (the AI crawlers on the list, and the records we keep), how the failure is detected, and how it is contained. Three things hold in every case.
- People and search crawlers stay outside it. The rule matches on user agent only, and it lists every search crawler under
missing, so their requests never reach us. A failure on our side cannot change what they get or how fast they get it. The exceptions are the link previews and the two optional files, noted where they apply. - Nothing is left behind in a cache. Every response from our edge service, its errors included, is marked
Cache-Control: private, no-store, so Vercel keeps no copy. Once a failure ends, the next request gets the right page. - Today we record only the AI version. We record a crawler visit when we serve the AI version of a page. A fall-back or an error leaves no record on our side. Your Vercel logs still show the request. Before the preview we will record every fall-back too, with its reason, so the crawler visits on measuring results include them.
The page has no AI version yet
| Your human layer | No change. Visitors and search crawlers get your page as they do today, on every page, at its normal speed. |
|---|---|
| Our layer | The AI crawler gets your normal page, status 200, instead of the AI version. This affects that page only, until its AI version is published. The crawler waits slightly longer: 0.7 to 1.7 seconds for the whole round trip in our 22 October check. If the rule went live today this would apply to every page, English and Spanish: the AI versions are still in review and none is live. Today this leaves no record on our side. |
| Detected by | This is the designed behaviour, not an alarm. Each such response is marked x-answershare-variant: passthrough and x-answershare-passthrough-reason: miss. |
| Contained by | The fall-back, automatically, on each request. There is nothing to revert. It ends for a page when that page's AI version is published. |
Our content service fails or is slow
| Your human layer | No change. |
|---|---|
| Our layer | The AI crawler gets your normal page, status 200, instead of the AI version. It gets it at once if our content service errors, or after our time budget if the service is slow. This covers every page for as long as the fault lasts. Nothing is recorded on our side today. |
| Detected by | Our every-minute uptime check, once your site is added to it (see the note below). |
| Contained by | The fall-back, automatically, on each request. We fix the cause on our side. If it is not fixed within the hour, the stop conditions call for a revert. |
Your site is slow or down when our edge service fetches your page
| Your human layer | Whatever your site gives visitors at that moment. The rule adds nothing to it, because their requests never reach us. |
|---|---|
| Our layer | This happens only when a page also has no AI version, or our content service has failed. Our fall-back fetch then waits up to 10 seconds for your page. If your page has not arrived by then, or the fetch fails, the AI crawler gets status 502 from us instead of your slow page. Without the rule, it would have waited on your site directly. This lasts as long as your site is slow, and it leaves no record on our side today. |
| Detected by | Your own monitoring of your site. Our check sees a 502 marked x-answershare-passthrough-reason: live-failed. |
| Contained by | It ends when your site recovers. There is nothing to revert. |
Our edge service is down or unreachable
| Your human layer | No change for visitors or search crawlers. Two side effects reach people:
(1) If FacebookExternalHit stays on the list, links to your pages shared on Facebook, Messenger or WhatsApp during the outage may appear without a title and image. This applies to pages Meta has not already stored a preview for. Removing that entry removes this effect.
(2) If you keep Rule 2, /llms.txt and /llms-full.txt return an error to everyone during the outage. Both return 404 today. |
|---|---|
| Our layer | Every AI-crawler page request gets Vercel's 502, on every page, English and Spanish, for as long as the outage lasts. That includes user-triggered fetchers such as ChatGPT-User, Claude-User and Perplexity-User: an assistant fetching your page for a person's question gets no page. Nothing reaches us, so we record nothing. Only your Vercel logs show these requests. |
| Detected by | Our every-minute uptime check, once your site is added to it. It marks a check as down after 3 failures in a row, about 3 minutes. |
| Contained by | A revert, which only your team can make, because the rule lives in your deployment. The stop conditions call for one when failures pass 1% of AI-crawler requests in an hour, or run 15 minutes in a row. Instant Rollback takes effect without a rebuild. We time it on the preview (test T18). Until the rollback lands, AI crawlers keep getting 502. People and search crawlers are unaffected throughout. |
Our edge service accepts the connection but never answers
| Your human layer | The same as the case above. Visitors and search crawlers see no change. Shared-link previews and the two optional files wait up to 120 seconds and then fail. |
|---|---|
| Our layer | Each AI-crawler request waits up to Vercel's 120 seconds, then gets 502. Our edge service caps its own work at 2.5 seconds for the AI version plus 10 seconds for the fall-back. So this case arises only if the edge platform itself hangs. Nothing is recorded on our side. |
| Detected by | The same every-minute check. It counts a check as failed if no answer arrives within 15 seconds. |
| Contained by | The same revert as the case above. |
The alternative, if you prefer it. If HOLT would rather AI crawlers always fall back to your page, even when our edge service is down, the way to do that is a small Next.js middleware with a timeout: if we do not answer within 2.5 seconds, the request falls through to your normal page. That is the middleware design in our 8 October overview, with the credential kept in your environment variables as you asked. Its costs are the ones listed above: code on every page request, a credential in your environment variables, and upkeep across Next.js releases. We recommend the rule. We will provide the middleware for review if you choose it.
The snippet
For next.config.js. If your config is next.config.mjs or next.config.ts, the same object goes in your existing export. If you already have rewrites, keep them: a rewrites() that returns an array maps to afterFiles below.
// AnswerShare AI-crawler rule for www.texasfirstrentals.com (rule v0.1, test run)
// Crawler names: AnswerShare aryah-shared src/bot-classification.ts,
// AI_BOTS and SEARCH_BOTS at commit b43382d (2 October 2026).
// Matching is by user agent only. No IP or network lookups.
// To remove: delete this block and the answershareRewrites entry in rewrites().
const ANSWERSHARE_ORIGIN = 'https://customers.texasfirstrentals.production.answershare.com';
// AI crawlers and AI agents that get the AI version of a page.
const AI_CRAWLERS = [
// OpenAI
'GPTBot', 'OAI-SearchBot', 'ChatGPT-User', 'ChatGPT',
// Anthropic
'ClaudeBot', 'Claude-SearchBot', 'Claude-User', 'claude-web', 'anthropic-ai',
// Perplexity
'PerplexityBot', 'Perplexity-User',
// Google AI agents: not search crawlers. Remove any you prefer.
'Gemini-Deep-Research', 'Gemini-Research', 'Gemini-User', 'GeminiBot', 'Gemini-AI',
'GoogleAgent-Mariner', 'GoogleAgent-URLContext', 'Google-CloudVertexBot',
'GoogleOther', 'Google-Extended',
// Apple: AI only. Plain Applebot is a search crawler and is excluded below.
'Applebot-Extended',
// Meta
'Meta-ExternalAgent', 'FacebookExternalHit',
// Others
'Bytespider', 'Amazonbot', 'YouBot', 'Diffbot', 'CCBot', 'Cohere-AI',
'DeepSeekBot', 'MistralAI-User', 'Qwen-Bot', 'GrokBot', 'xAI-Grok', 'Grok-DeepSearch',
// AnswerShare's own measurement crawler
'AnswerShareBot',
];
// Search crawlers always get your normal site, even if a user agent
// also contains a name from the list above.
const SEARCH_CRAWLERS = [
'Googlebot', 'Googlebot-Image', 'Google-InspectionTool', 'Bingbot', 'Applebot',
'DuckDuckBot', 'YandexBot', 'Baiduspider', 'PetalBot',
];
// Next.js anchors header patterns (^...$) and matches them case-sensitively.
// Each name matches as written above and in lower case.
// Names contain only letters, digits and hyphens, so no escaping is needed.
const uaPattern = (names) =>
`.*(?:${[...new Set(names.flatMap((n) => [n, n.toLowerCase()]))].join('|')}).*`;
const answershareRewrites = [
// Rule 1: page requests from a named AI crawler get the AI version of that page.
{
// Every page path except /_next/, /_vercel/, /api/, /.well-known/
// and any path ending in a file extension (assets, robots.txt, sitemap.xml).
source: '/:path((?!(?:_next|_vercel|api|\\.well-known)(?:/|$)|.*\\.[A-Za-z0-9]+$).*)',
has: [{ type: 'header', key: 'user-agent', value: uaPattern(AI_CRAWLERS) }],
missing: [
{ type: 'header', key: 'user-agent', value: uaPattern(SEARCH_CRAWLERS) },
{ type: 'header', key: 'rsc' }, // in-app navigation data
{ type: 'header', key: 'next-action' }, // form submissions
{ type: 'header', key: 'x-answershare-passthrough' }, // our fall-back fetch; stops loops
],
destination: `${ANSWERSHARE_ORIGIN}/:path`,
},
// Rule 2: two public files, identical for every visitor and crawler.
// Both return 404 on your site today.
{ source: '/llms.txt', destination: `${ANSWERSHARE_ORIGIN}/llms.txt` },
{ source: '/llms-full.txt', destination: `${ANSWERSHARE_ORIGIN}/llms-full.txt` },
];
module.exports = {
// ...your existing settings, unchanged...
async rewrites() {
return {
beforeFiles: answershareRewrites,
afterFiles: [], // your existing rewrites, if any
fallback: [],
};
},
};
Requires Next.js 13.3 or later (for missing).
Question for HOLT: Which Next.js version does the site run?
Rule 2 is optional for the test run. It adds two files that do not exist today and serves them the same way to everyone, so it changes nothing that people or search engines currently get. If you would rather leave it out, delete those two lines. Vercel does not allow rewrites of /.well-known/, so any file we supply for that folder would be a static file you commit. We are not asking for one in the test run.
What your team does
Nothing goes live from these steps; they only prepare your preview.
- Put the rule in next.config.js.
Click flow: your code repository for www.texasfirstrentals.com (GitHub, GitLab or Bitbucket, whichever you use) > the project root folder > next.config.js (or next.config.mjs / next.config.ts) > the rewrites() function > the "beforeFiles" list.
Required state: the AnswerShare block from the attached rule file sits inside "beforeFiles". Keep your existing rewrites where they are (they stay in "afterFiles").
You should see: a rewrites() function that returns beforeFiles, afterFiles and fallback, with the AnswerShare block first. - Make sure vercel.json has no AnswerShare rule.
Click flow: the same repository > the project root folder > vercel.json > the "rewrites" array.
Required state: no entry whose destination contains answershare.com.
You should see: either no vercel.json rewrites at all, or only your own. - Put the change in its own deployment, so Instant Rollback removes only this.
Click flow: your repository > create a branch > commit the next.config.js change > open a pull request.
Required state: the pull request contains only the next.config.js change.
You should see: Vercel adds a Preview deployment to the pull request. - Open the Preview deployment so we can test it.
Click flow: https://vercel.com/dashboard > your Texas First Rentals project > Deployments > the newest "Preview" row > Visit.
Required state: the deployment status is Ready.
You should see: your normal site in the browser. Nothing changes for a person visiting. - Tell us the Preview address and how we get through Vercel Deployment Protection.
Click flow: Vercel dashboard > your project > Settings > Deployment Protection.
Required state: either "Protection Bypass for Automation" is enabled and you read the value to us on a call (never in email), or you allow our test server address for the preview.
You should see: the setting shown as Enabled, with a bypass value you can reveal.
Revert in one step
One step: in Vercel, use Instant Rollback to return production to the deployment before the rule. It takes effect without a rebuild. Ship the rule in a deployment of its own so that a rollback removes nothing else.
Question for HOLT: Is Instant Rollback available on your Vercel plan, and will your team use it for this rollback?
Permanent: delete the AnswerShare block and the answershareRewrites entry, and deploy. Nothing else in your project depends on it, and there is nothing to clean up afterwards: no DNS record, no environment variable, no secret.
We rehearse both on the preview before go-live (test T18).
The crawler list, entry by entry
"User-triggered" means the crawler fetches a page because a person just asked an assistant something. "Crawler" means a background index or training crawl. We use this split for the user-intent share on measuring results. Entries marked "Review" are ones we suggest your team looks at.
| Name in the rule | Operator | Type | Note |
|---|---|---|---|
| GPTBot | OpenAI | Crawler | |
| OAI-SearchBot | OpenAI | User-triggered | ChatGPT search. |
| ChatGPT-User, ChatGPT | OpenAI | User-triggered | "ChatGPT" also catches other ChatGPT fetchers. |
| ClaudeBot | Anthropic | Crawler | |
| Claude-SearchBot, Claude-User | Anthropic | User-triggered | |
| claude-web, anthropic-ai | Anthropic | Crawler | Older names. |
| PerplexityBot | Perplexity | Crawler | |
| Perplexity-User | Perplexity | User-triggered | |
| Gemini-User, Gemini-Deep-Research | User-triggered | Review: Google AI agents, not search crawlers. | |
| Gemini-Research, GeminiBot, Gemini-AI | Crawler | Review: Google AI agents, not search crawlers. | |
| GoogleAgent-Mariner, GoogleAgent-URLContext | User-triggered | Review. URLContext is the fetcher Gemini uses when a person hands it a URL. | |
| Google-CloudVertexBot | Crawler | Review. Vertex AI Agent Builder; no effect on Google Search. | |
| GoogleOther | Crawler | Review. Google's general-purpose crawler outside Search. | |
| Google-Extended | Crawler | A robots.txt token. Google crawls with Googlebot, which is excluded, so this entry is not expected to match any request. | |
| Applebot-Extended | Apple | Crawler | A robots.txt token. Apple crawls with Applebot, which is excluded, so this entry is not expected to match any request. |
| Meta-ExternalAgent | Meta | Crawler | |
| FacebookExternalHit | Meta | Crawler | Review. Meta also uses this agent to build link previews when people share your pages on Facebook, Messenger or WhatsApp. If it stays, those previews are built from the AI version, and the AI versions we build today carry no Open Graph title, description or image (checked on the five sample pages). Remove this entry if you want shared links to keep your own preview. |
| Bytespider | ByteDance | Crawler | |
| Amazonbot | Amazon | Crawler | |
| YouBot | You.com | User-triggered | |
| Diffbot | Diffbot | Crawler | |
| CCBot | Common Crawl | Crawler | |
| Cohere-AI | Cohere | Crawler | |
| DeepSeekBot | DeepSeek | Crawler | |
| MistralAI-User | Mistral | User-triggered | |
| Qwen-Bot | Alibaba | Crawler | |
| GrokBot, xAI-Grok, Grok-DeepSearch | xAI | Crawler | |
| AnswerShareBot | AnswerShare | Crawler | Our own measurement crawler, so our scores read what AI crawlers read. Review: you may remove it, and our measurements would then read your normal page. |