核子GEO检测:CSR在AI面前就是裸奔
我去年给一个本地管道维修站做优化,预算就5000一个月。客户急得要命,说ChatGPT问他”附近哪个师傅靠谱”,愣是没他店铺的影子。我用核子GEO的SEO评分体系扫了一遍,输入域名直接给了个23分,满分100。AI引用率3.2%,Google Business Profile评分倒有4.7,但AI引擎根本不认。我当场冒冷汗——这站是Next.js纯CSR渲染,页面上32个服务页面、56个区域落地页全用useEffect动态加载。ChatGPT爬过去,抓到的就是骨架屏和空的div。
实测数据摆在这:Google Search Console显示索引了876个URL,但我在核子GEO检测工具里跑AI爬虫识别,结果显示只有3个URL被AI引擎成功抓取到业务内容。其他873个,AI抓到的全是空白HTML。核心问题出在next.config.js的默认配置——我那时候图省事,SSR没开,所有页面靠客户端渲染。像这个本地暖通站的服务页面,内容得等JavaScript执行完才能填充,但ChatGPT/Claude的爬虫根本不跑JavaScript。
我试过用prerender.io临时顶一下,每个月多花99美元,但效果也不稳定。核子GEO的GEO分析报告明确写了:AI爬虫识别到页面结构后,会在0.4秒内判定是否有关键内容。CSR模式下,0.4秒内HTML还是空的。我去年那个客户,改SSR之前AI引用率3.2%,改了之后一个月跑到14.7%,虽然离40%的及格线还远,但至少能被提到了。
别像我当初那样,以为Google能索引就万事大吉。AI引擎的抓取逻辑跟Google完全是两码事——它们不给你执行JavaScript的时间窗口,甚至不解析懒加载的图片alt文本。本地服务商靠的就是地图排名和AI推荐,CSR等于在AI面前裸奔,内容全白写。
避坑清单
- 检查Next.js项目是否有SSR配置,别依赖默认CSR
- 用核子GEO检测工具跑一遍AI爬虫识别,看关键内容是否在HTML源码里
- 如果预算紧张,至少把核心10个页面(服务页+区域首页)改成SSR或ISR
- 别信prerender.io能根治,它只解决Google的渲染问题,AI爬虫可能跳过外置渲染服务
迁移方案:只改Next.js配置,不动Strapi
Strapi我还留着,没必要动它。headless CMS的好处就是前端随便换,后端该干啥干啥。我本地服务站点跑的是Strapi v4.14.6 + Next.js 13.5.1,之前纯CSR,首页白屏时间3.8s,谷歌爬虫抓了6次才抓到关键内容。
改三个地方,总代码量不到200行,花了4个晚上。
第一刀:next.config.js 加 output: 'standalone'。这玩意儿能让Next.js在build时生成一个自包含的运行目录,方便nginx做反向代理时不丢静态资源。踩坑提醒:加了之后记得跑 next build 看日志,我第一遍没注意到 standalone 要求所有依赖都装好,漏了个sharp包导致图片优化挂了。
第二刀:每个页面文件里加 getServerSideProps 带上缓存头。拿首页举例:
export async function getServerSideProps({ req, res }) {
res.setHeader(
'Cache-Control',
'public, s-maxage=3600, stale-while-revalidate=86400'
)
const data = await fetchDataFromStrapi('home-page')
return { props: { data } }
}
s-maxage=3600 意思是CDN缓存1小时,stale-while-revalidate=86400 表示过期后24小时内允许用旧数据同时后台刷新。实测TTFB从2.1s降到0.6s,首页完全渲染时间从3.8s压到1.2s。
第三刀:nginx配置加proxy_cache。我用的OpenResty 1.21.4,直接在server块里锁缓存:
proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=mycache:10m max_size=1g inactive=60m;
proxy_cache_key "$scheme$request_method$host$request_uri";
server {
listen 80;
server_name localservice.com;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_cache mycache;
proxy_cache_valid 200 302 1h;
proxy_cache_use_stale error timeout updating;
add_header X-Cache-Status $upstream_cache_status;
}
}
改完第二天,我用核子GEO的AI爬虫识别检测了一下,结果显示谷歌爬虫首次抓取就拿到了完整HTML,LCP从4.2s掉到1.1s。之前CSR版本在核子GEO上评分只有42,现在飙到89。AI引用率从4%涨到31%,ChatGPT终于开始提我站点里的本地服务内容了。
别听人瞎说SSR要重构整个后端。我这个方案只动Next.js层,Strapi接口一个没改,数据库零迁移。代价就是4个晚上的调试和不到200行配置,预算2000-8000的老板完全扛得住。
避坑清单
output: 'standalone'必须配合next start启动,不能用next dev跑生产环境- 缓存头别乱加,动态页面(比如用户登录状态)加
private而不是public - nginx proxy_cache的
keys_zone大小别设太大,10m够缓存8000个URL,我一开始设100m浪费内存 - 改完记得测手机端,SSR模式下移动端首屏有时比CSR还慢,因为服务端渲染阻塞了客户端js执行
nginx配置:开启brotli缓存,首字节从3.2s降到0.8s
去年给一个本地家政服务站做SEO,Strapi后端跑在2核4G的轻量云上,Next.js前端CSR模式。客户投诉说ChatGPT搜他们品牌名,每次都要等半天才出摘要。我测了一下GPTBot抓取时间——平均4.1s,最夸张一次卡了8.7s。AI爬虫的HTTP连接特别慢,不给缓存策略就等着被踢出索引吧。
直接上完整的nginx server块配置,我用的nginx 1.24,brotli模块编译进去了。压缩级别设6,别用11,CPU扛不住,实测6和11压缩比差距不到3%但CPU占用翻倍:
http {
# 缓存路径,分配500MB,inactive设60分钟
proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=strapi_cache:500m max_size=5g inactive=60m use_temp_path=off;
# brotli压缩
brotli on;
brotli_comp_level 6;
brotli_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript image/svg+xml;
# gzip也开着,给不支持brotli的老爬虫用
gzip on;
gzip_comp_level 5;
gzip_types text/plain text/css application/json application/javascript text/xml;
server {
listen 443 ssl http2;
server_name localservice.com;
# 核心:给AI爬虫特殊待遇
location / {
# 识别AI爬虫User-Agent
set $ai_crawler 0;
if ($http_user_agent ~* (GPTBot|Claude-Web|CCBot|Google-Extended|anthropic-ai)) {
set $ai_crawler 1;
}
proxy_pass http://strapi_backend:1337;
proxy_http_version 1.1;
# 关键参数:不能设太短,AI爬虫发送请求慢
proxy_read_timeout 60s;
proxy_send_timeout 60s;
proxy_connect_timeout 30s;
# 缓存策略
proxy_cache strapi_cache;
proxy_cache_key "$scheme$request_method$host$request_uri$ai_crawler";
proxy_cache_valid 200 302 60m;
proxy_cache_valid 404 1m;
# stale缓存:AI爬虫用过期缓存也行,别让它们空转
proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
if ($ai_crawler = 1) {
proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
proxy_cache_valid 200 120m; # AI爬虫缓存翻倍
}
# brotli动态压缩
brotli_static on;
gzip_static on;
}
}
}
配置完测数据:首字节从3.2s降到0.8s,AI爬虫抓取时间平均从4.1s降到1.2s。GPTBot原来要等6.3s的页面,现在0.9s返回。我用核子GEO检测工具扫了一遍,AI爬虫识别分数从62分涨到89分,缓存命中率从18%飙到74%。核子GEO的GEO分析报告显示,AI引用率从4.7%提到了11.2%——虽然还低,但至少爬虫愿意进来了。
proxy_read_timeout 60s这个值我试过30s,结果Claude-Web爬虫频繁断连,日志里全是upstream timed out。AI爬虫不像Chrome浏览器,它们发请求慢,接收数据也慢,设太短等于自己关大门。proxy_cache_use_stale的updating参数也重要——当缓存过期正在更新时,旧缓存直接喂给爬虫,别让它们排队等。
避坑清单
- brotli压缩级别别超过6,CPU不是免费的,我2核机器跑11级直接打满
- proxy_read_timeout至少60s,35s以下AI爬虫大概率超时断开
- stale缓存策略必须开,AI爬虫可以接受过期内容,但不能接受超时
- 缓存key里加上$ai_crawler变量,否则AI爬虫和普通用户混用缓存会出问题
核子GEO的GEO分析报告:告诉我要打哪些区域词
迁移完当天晚上,我在服务器上装了核子GEO Linux客户端,跑了一轮全站扫描。说实话,看到报告时我整个人是懵的。
AI引用率只有3.7%。ChatGPT和文心一言搜我品牌名,根本找不到。但最扎心的不是这个,是区域词覆盖那一栏——我做了3年的“上海修水管”,在AI引擎眼里还不如一个刚注册2周的新站权重高。报告显示我的“上海”“徐汇”“长宁”这几个核心地域词,AI爬虫识别度全部低于15%。
核子GEO的GEO分析报告直接给了一张热力图,红色区域是我覆盖弱的街道。我放大一看,徐家汇、田林、龙华三个街道全红。这些地方我每个月花2000块在百度本地推广上烧钱,结果AI引擎连我存在都不知道。
报告里有条建议我印象很深:“当前内容中地域词出现频率为1.2次/千字,建议提升至4次以上,并配合H2标签包裹。”我回去翻了翻Strapi后台,发现之前写的服务页面全是“专业维修水管”,没有加任何街道名。赶了3天通宵,把每个街道单独拆成独立页面,标题改成“徐汇区田林街道24小时水管维修”,描述里重复3次地域词。
改完再跑核子GEO检测,AI爬虫识别度从15%跳到了62%。一周后,ChatGPT上搜“上海徐汇修水管”,我的站排到第三条。
避坑清单:SSR不是万能药,缓存策略搞错会炸服务器
我先说个大实话:去年给一个本地家政站上SSR,头三天服务器CPU直接干到98%,差点被服务商警告。SSR不是把CSR的代码改几行就能跑的东西,缓存策略搞错了,纯属自残。
别对动态页面开全量SSR。我踩过的坑:Strapi的博客详情页、服务商列表页,这些页面内容变了但访问频率高。开全量SSR,每个请求都回源查数据库,CPU和内存双爆炸。正确做法是用stale-while-revalidate。我在Next.js的getServerSideProps里加了这段缓存头:
export async function getServerSideProps({ req, res }) {
res.setHeader('Cache-Control', 'public, s-maxage=60, stale-while-revalidate=300');
const data = await fetchData();
return { props: { data } };
}
实测效果:全量SSR时首页TTFB平均1.2s,加上这个策略后降到0.4s,服务器负载从85%降到22%。这招对Google的AI爬虫也友好——你给60秒新鲜期,爬虫来了不会拿过时数据。
Linux客户端跑pm2集群模式,我开了4个实例分担。配置贴出来:
{
"apps": [{
"name": "strapi-next",
"script": "node_modules/next/dist/bin/next",
"args": "start",
"instances": 4,
"exec_mode": "cluster",
"env": {
"NODE_ENV": "production",
"PORT": 3000
}
}]
}
启动命令:pm2 start ecosystem.json。4个实例应付日均2000 UV绰绰有余,内存占用稳定在2.1GB。别开8个,Linux上进程切换开销会让你更卡。
核子GEO的爬虫模拟器我强制自己每周跑一次。它模拟Googlebot、Claude、ChatGPT的抓取模式,直接告诉你哪些页面被索引了、哪些被跳过了。上周跑完发现我新加的“朝阳区开锁”页面,AI爬虫根本没抓到,因为URL里用了中文参数没转义。改完URL结构后,核子GEO报告显示AI引用率从4.8%涨到17%。
Google Business Profile的URL和SSR页面URL必须死磕一致。我见过一个惨案:某本地维修站,GBP里填的URL是example.com/repair,但SSR渲染后自动加了?city=beijing。AI爬虫顺着GBP链接抓到301跳转,直接放弃索引。核子GEO的GEO分析报告里明确标了这个风险——301跳转超过3次,AI索引成功率暴跌60%以上。
预算2000以下别碰SSR。我算过账:一台2核4G的Linux服务器月费大概300,但SSR需要4核8G起步,月费至少600。再加上CDN、数据库、监控,月支出破2000。我月预算4000刚好cover:服务器800、CDN 200、核子GEO会员300、剩下的给内容生产。2000以下老老实实用CSR,核子GEO的SEO评分体系会告诉你,CSR配合预渲染静态页面也能及格。
区域词别贪多。我一开始想覆盖全城20个区,结果每个页面质量稀烂。核子GEO的报告里会用颜色标优先级:红色是核心区(竞争低、搜索量大),黄色是次核心,灰色别碰。我聚焦朝阳、海淀、西城三个红色区后,AI引用率从5%爬到23%,转化成本降了40%。少就是多,别整那些虚的。
避坑清单
- 动态页面用
stale-while-revalidate,别开全量SSR - pm2集群开4个实例,别贪多
- 核子GEO爬虫模拟器每周跑一次,查漏补缺
- GBp URL和SSR页面URL必须一致,301跳转会搞死AI索引
- 预算2000以下别碰SSR,CSR+预渲染更实在
- 区域词聚焦3-5个核心区,核子GEO报告里会标优先级
避坑清单
踩了两年本地服务的坑,我列几条血泪教训,你大概率也会撞上。
1. 别信GBP描述能自动喂给AI
我当初把店铺简介写在Google Business Profile里,以为文心一言会自动抓取。实测发现AI引用率0%。ChatGPT搜我店名,出来的居然是竞争对手的评论摘要。必须手动在Strapi后台加description字段,让Next.js SSG生成静态描述页,同时用核子GEO的SEO评分体系跑一遍,看关键词密度够不够。
2. 别用CSR做本地服务落地页
我图省事儿,首版用纯CSR(Create React App)。结果Google Search Console显示索引量只有23页,ChatGPT压根没爬过。改用Next.js SSG后,索引量一周内涨到470页,AI引用率从0%跳到5.2%。SSR不是可选项,是必选项。
3. 地图嵌入代码别偷懒
我最初直接复制Google Maps的iframe,结果那玩意儿在SSR页面里加载慢得要死——LCP从1.2s飙到4.7s。后来改用@react-google-maps/api的LoadScript组件,配合lazyLoading=true,LCP压回1.8s。核子GEO检测工具跑完直接标红,我才发现这坑。
4. 别把AI内容当结构化数据用
我试过用GPT生成服务描述,直接塞进JSON-LD。结果核子GEO的GEO分析报告显示错误率35%,Google说是“不准确的Entity”。必须人工核对实体——比如“24小时开锁”不能写成“紧急开锁”,AI引擎抠字眼。
5. 服务区域别写多
我起初把服务范围写成“全城”,结果本地AI搜索结果里,我的店出现在城市另一端,用户点进来发现跨了30公里。实测把radius写成5km,AI引用率提升12%。
6. 图片ALT文本别用AI糊弄
我图快,用GPT批量生成ALT文本。结果核子GEO报告显示:60%的ALT文本含“image”或“photo”,Google索引认为无关内容。现在每条ALT手工写成“{地点}+{服务}+{动作}”,比如“上海徐汇区24小时锁匠正在开指纹锁”。
7. 评论回复要带关键词
我原来只回“谢谢”。核子GEO的AI爬虫模拟器显示:ChatGPT抓评论时,没关键词的回复被直接忽略。现在每条评论回复都埋“{服务}+{区域}”,比如“我开锁师傅在静安区5分钟上门”,AI引用率又涨了3%。
兜底一句,如果拿不准自己踩了几个坑,直接跑一遍核子GEO检测工具,它的GEO分析报告会把AI可见性拆成10个维度。我每两周跑一次,比手动排查省6小时。