https://www.searchenginejournal.com/create-your-own-chatgpt-agent-for-on-page-seo-audits/546016/
Автоматизируйте свои SEO-аудиты с помощью специального агента ChatGPT. Извлекайте HTML, анализируйте контент и внедряйте действенные рекомендации по SEO без особых усилий.
Людвиг Махян
VIP-УЧАСТНИК
Людвиг Махян
14 мая 2025 г.
⋅
15 мин чтения
53
АКЦИИ
15К
ЧИТАЕТ
Создайте собственного агента ChatGPT для аудита SEO на странице
ChatGPT — это больше, чем просто платформа для подсказок и ответов. Вы можете отправлять подсказки, чтобы попросить о помощи с SEO, но он становится более мощным, когда вы создаете своего собственного агента.
Я провожу много SEO-аудитов (это необходимость для корпоративного сайта ), поэтому я искал способ оптимизировать некоторые из этих процессов.
Как я это сделал? Создав агент ChatGPT , которым я собираюсь поделиться с вами, чтобы вы могли настраивать и изменять его в соответствии со своими потребностями.
Я постараюсь изложить все максимально «нетехнично», но просто следуйте инструкциям, и все должно работать.
Я собираюсь объяснить следующие шаги.
Конфигурация собственного ChatGPT.
Создание собственного кода Cloudflare для извлечения HTML-данных страницы.
Задействуйте ваших агентов по SEO-аудиту.
В конце у вас будет бот, который предоставит вам информацию, такую как:
Пользовательский ChatGPT для SEO
Пользовательский ChatGPT для SEO (изображение автора, май 2025 г.)
Вы также получите список практических шагов, которые следует предпринять для улучшения SEO на основе выводов агента.
Создание рабочего процесса Cloudflare Pages для вашего агента
Специалисты Cloudflare Pages помогают вашему агенту собирать информацию с веб-сайта, который вы пытаетесь проанализировать, и просматривать его текущее состояние SEO.
Для начала вы можете использовать бесплатную учетную запись. Зарегистрироваться можно, выполнив следующие действия:
Переходим на http://pages.dev/
Создание учетной записи
Я использовал Google для регистрации, потому что это проще, но выбирайте наиболее удобный для вас способ. Вы окажетесь на экране, который выглядит примерно так:
Панель управления Cloudflare
Панель управления Cloudflare (скриншот из Cloudfare, май 2025 г.)
Перейдите в меню Добавить > Работники.
Добавить работника Cloudflare
Добавьте Cloudflare Worker (скриншот из Cloudfare, май 2025 г.)
Затем вы можете выбрать шаблон, импортировать репозиторий или начать с Hello World! Я выбрал вариант Hello World, так как он самый простой в использовании.
Выбор Cloudflare Worker
Выбор Cloudflare Worker (скриншот из Cloudfare, май 2025 г.)
Пройдите через следующий экран и нажмите « Развернуть ». Вы окажетесь на экране с надписью «Успех! Ваш проект развернут в регионе: Земля».
Не покидайте эту страницу.
Вместо этого нажмите « Изменить код », удалите весь существующий код и введите в редактор следующий код:
addEventListener('fetch', event => {
event.respondWith(handleRequest(event.request));
});
async function handleRequest(request) {
const { searchParams } = new URL(request.url);
const targetUrl = searchParams.get('url');
const userAgentName = searchParams.get('user-agent');
if (!targetUrl) {
return new Response(
JSON.stringify({ error: "Missing 'url' parameter" }),
{ status: 400, headers: { 'Content-Type': 'application/json' } }
);
}
const userAgents = {
googlebot: 'Mozilla/5.0 (Linux; Android 6.0.1; Nexus 5X Build/MMB29P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.6167.184 Mobile Safari/537.36 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)',
samsung5g: 'Mozilla/5.0 (Linux; Android 13; SM-S901B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36',
iphone13pmax: 'Mozilla/5.0 (iPhone14,3; U; CPU iPhone OS 15_0 like Mac OS X) AppleWebKit/602.1.50 (KHTML, like Gecko) Version/10.0 Mobile/19A346 Safari/602.1',
msedge: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.135 Safari/537.36 Edge/12.246',
safari: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_2) AppleWebKit/601.3.9 (KHTML, like Gecko) Version/9.0.2 Safari/601.3.9',
bingbot: 'Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko; compatible; bingbot/2.0; +http://www.bing.com/bingbot.htm) Chrome/',
chrome: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36',
};
const userAgent = userAgents[userAgentName] || userAgents.chrome;
const headers = {
'User-Agent': userAgent,
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Accept-Encoding': 'gzip',
'Cache-Control': 'no-cache',
'Pragma': 'no-cache',
};
try {
let redirectChain = [];
let currentUrl = targetUrl;
let finalResponse;
// Follow redirects
while (true) {
const response = await fetch(currentUrl, { headers, redirect: 'manual' });
// Add the current URL and status to the redirect chain only if it's not already added
if (!redirectChain.length || redirectChain[redirectChain.length - 1].url !== currentUrl) {
redirectChain.push({ url: currentUrl, status: response.status });
}
// Check if the response is a redirect
if (response.status >= 300 && response.status < 400 && response.headers.get('location')) {
const redirectUrl = new URL(response.headers.get('location'), currentUrl).href;
currentUrl = redirectUrl; // Follow the redirect
} else {
// No more redirects; capture the final response
finalResponse = response;
break;
}
}
if (!finalResponse.ok) {
throw new Error(`Request to ${targetUrl} failed with status code: ${finalResponse.status}`);
}
const html = await finalResponse.text();
// Robots.txt
const domain = new URL(targetUrl).origin;
const robotsTxtResponse = await fetch(`${domain}/robots.txt`, { headers });
const robotsTxt = robotsTxtResponse.ok ? await robotsTxtResponse.text() : 'robots.txt not found';
const sitemapMatches = robotsTxt.match(/Sitemap:\s*(https?:\/\/[^\s]+)/gi) || [];
const sitemaps = sitemapMatches.map(sitemap => sitemap.replace('Sitemap: ', '').trim());
// Metadata
const titleMatch = html.match(/<title[^>]*>\s*(.*?)\s*<\/title>/i);
const title = titleMatch ? titleMatch[1] : 'No Title Found';
const metaDescriptionMatch = html.match(/<meta\s+name=["']description["']\s+content=["'](.*?)["']\s*\/?>/i);
const metaDescription = metaDescriptionMatch ? metaDescriptionMatch[1] : 'No Meta Description Found';
const canonicalMatch = html.match(/<link\s+rel=['"]canonical['"]\s+href=['"](.*?)['"]\s*\/?>/i);
const canonical = canonicalMatch ? canonicalMatch[1] : 'No Canonical Tag Found';
// Open Graph and Twitter Info
const ogTags = {
ogTitle: (html.match(/<meta\s+property="og:title"\s+content="(.*?)"\s*\/?>/i) || [])[1] || 'No Open Graph Title',
ogDescription: (html.match(/<meta\s+property="og:description"\s+content="(.*?)"\s*\/?>/i) || [])[1] || 'No Open Graph Description',
ogImage: (html.match(/<meta\s+property="og:image"\s+content="(.*?)"\s*\/?>/i) || [])[1] || 'No Open Graph Image',
};
const twitterTags = {
twitterTitle: (html.match(/<meta\s+(name|property)="twitter:title"\s+content="(.*?)"\s*\/?>/i) || [])[2] || 'No Twitter Title',
twitterDescription: (html.match(/<meta\s+(name|property)="twitter:description"\s+content="(.*?)"\s*\/?>/i) || [])[2] || 'No Twitter Description',
twitterImage: (html.match(/<meta\s+(name|property)="twitter:image"\s+content="(.*?)"\s*\/?>/i) || [])[2] || 'No Twitter Image',
twitterCard: (html.match(/<meta\s+(name|property)="twitter:card"\s+content="(.*?)"\s*\/?>/i) || [])[2] || 'No Twitter Card Type',
twitterCreator: (html.match(/<meta\s+(name|property)="twitter:creator"\s+content="(.*?)"\s*\/?>/i) || [])[2] || 'No Twitter Creator',
twitterSite: (html.match(/<meta\s+(name|property)="twitter:site"\s+content="(.*?)"\s*\/?>/i) || [])[2] || 'No Twitter Site',
twitterLabel1: (html.match(/<meta\s+(name|property)="twitter:label1"\s+content="(.*?)"\s*\/?>/i) || [])[2] || 'No Twitter Label 1',
twitterData1: (html.match(/<meta\s+(name|property)="twitter:data1"\s+content="(.*?)"\s*\/?>/i) || [])[2] || 'No Twitter Data 1',
twitterLabel2: (html.match(/<meta\s+(name|property)="twitter:label2"\s+content="(.*?)"\s*\/?>/i) || [])[2] || 'No Twitter Label 2',
twitterData2: (html.match(/<meta\s+(name|property)="twitter:data2"\s+content="(.*?)"\s*\/?>/i) || [])[2] || 'No Twitter Data 2',
twitterAccountId: (html.match(/<meta\s+(name|property)="twitter:account_id"\s+content="(.*?)"\s*\/?>/i) || [])[2] || 'No Twitter Account ID',
};
// Headings
const headings = {
h1: [...html.matchAll(/<h1[^>]*>(.*?)<\/h1>/gis)].map(match => match[1]),
h2: [...html.matchAll(/<h2[^>]*>(.*?)<\/h2>/gis)].map(match => match[1]),
h3: [...html.matchAll(/<h3[^>]*>(.*?)<\/h3>/gis)].map(match => match[1]),
};
// Images
const imageMatches = [...html.matchAll(/<img\s+[^>]*src="(.*?)"[^>]*>/gi)];
const images = imageMatches.map(img => img[1]);
const imagesWithoutAlt = imageMatches.filter(img => !/alt=".*?"/i.test(img[0])).length;
// Links
const linkMatches = [...html.matchAll(/<a\s+[^>]*href="(.*?)"[^>]*>/gi)];
const links = {
internal: linkMatches.filter(link => link[1].startsWith(domain)).map(link => link[1]),
external: linkMatches.filter(link => !link[1].startsWith(domain) && link[1].startsWith('http')).map(link => link[1]),
};
// Schemas (JSON-LD)
const schemaJSONLDMatches = [...html.matchAll(/<script[^>]*type="application\/ld\+json"[^>]*>(.*?)<\/script>/gis)];
const schemas = schemaJSONLDMatches.map(match => {
try {
return JSON.parse(match[1].trim());
} catch {
return { error: "Invalid JSON-LD", raw: match[1].trim() };
}
});
// Microdata
const microdataMatches = [...html.matchAll(/<[^>]*itemscope[^>]*>/gi)];
const microdata = microdataMatches.map(scope => {
const typeMatch = scope[0].match(/itemtype=["'](.*?)["']/i);
return {
type: typeMatch ? typeMatch[1] : 'Unknown',
raw: scope[0],
};
});
// Response Headers
const responseHeaders = Array.from(finalResponse.headers.entries());
// Construct final JSON output
return new Response(
JSON.stringify({
targetUrl,
redirectChain,
sitemaps,
metadata: { title, metaDescription, canonical },
headings,
schemas,
openGraph: ogTags,
twitterCards: twitterTags,
images: { total: images.length, withoutAlt: imagesWithoutAlt, imageURLs: images },
links,
microdata,
robotsTxt,
responseHeaders,
//rawHTML: html,
}),
{ headers: { 'Content-Type': 'application/json' } }
);
} catch (error) {
return new Response(
JSON.stringify({ error: error.message }),
{ status: 500, headers: { 'Content-Type': 'application/json' } }
);
}
}
На этом этапе вам нужно сделать две вещи:
Скопируйте URL-адрес в свой worker.
Разверните своего работника.
Это URL, который вам понадобится в следующем разделе. Вы можете найти его здесь:
Предварительный просмотр Cloudflare Worker
Предварительный просмотр Cloudflare Worker (скриншот из Cloudfare, май 2025 г.)
Обязательно нажмите « Deploy » перед выходом из экрана. Если вы хотите увидеть базовый вывод на этом этапе, вы можете это сделать.
Вставьте URL-адрес в адресную строку браузера и добавьте следующее после /?url=https://www.searchenginejournal.com.
Ваш URL-адрес будет выглядеть примерно так: https://YOURURL.workers.dev/?url=https://searchenginejournal.com.
Поменяйте URL на любой другой, чтобы протестировать это. На данном этапе это не «самый красивый», поэтому пришло время перейти к интересной части настройки собственного GPT.
Примечание: этот воркер не работает с сайтами, отрисовываемыми с помощью JavaScript. Но для всех остальных, использующих этот агент, он должен работать нормально. Не стесняйтесь улучшать его для работы с отрисовкой JavaScript.
Настройка собственного GPT для имитации моего агента
Сначала вам необходимо настроить GPT. Это можно сделать, открыв ChatGPT и перейдя в раздел « Изучить GPT » или просто перейдя по этой ссылке .
Исследуйте GPTИзучите GPT (скриншот из ChatGPT, май 2025 г.)
Затем вы перейдете к « + Создать »:
Пользовательский ChatGPT для SEO
Создать GPT (скриншот из ChatGPT, май 2025 г.)
Теперь там будет написано «Создать» и «Настроить». Перейдите в «Настроить » и начните вводить свою информацию.
Вы можете свободно что-то менять, но я рекомендую следовать всему, что я добавлю ниже, чтобы заложить основу вашего аудитора.
Вы добавите то, что я собираюсь перечислить в этом разделе:
Настроить GPT
Настройка GPT (скриншот из ChatGPT, май 2025 г.)
Name: OnPage SEO Audit
Description: Analyze SEO performance of any webpage using custom user-agents. Get detailed insights into metadata, redirect chains, Open Graph tags, Twitter Cards, sitemaps, and more. Perfect for SEO professionals and developers.
Instructions:
Trigger: When a user submits a URL (required) and an optional user-agent:
Instruction: Use the provided inputs to make an API request to retrieve SEO data. Default to the chrome user-agent if not provided.
Trigger: When the API returns valid data:
Instruction: Analyze the data and provide:
A summary of the page's SEO performance.
Actionable suggestions for improvement, categorized into metadata, technical SEO, and content.
Follow-up questions to clarify user priorities or goals, such as:
"Do you have specific goals for this page, such as improving search visibility, click-through rates, or user engagement?"
"Would you like me to focus on technical SEO or content-related improvements first?"
Example Response:
"The page's meta description is missing, which can impact click-through rates. Would you like me to suggest a draft description?"
Trigger: When the API returns HTTP 403:
Instruction:
Retry the request using the chrome user-agent.
If the issue persists:
Notify the user of the problem.
Suggest verifying the URL or user-agent compatibility.
Trigger: When the API returns a 400 error:
Instruction:
Clearly explain the error and provide actionable steps to resolve it (e.g., verify the URL format or ensure required parameters are provided).
Trigger: When data is incomplete or missing:
Instruction:
Request additional information from the user or permission to explore fallback data sources.
Example Follow-Up:
"The API response is missing a meta description for this page. Can you confirm if this was intentional, or should we explore other sources?"
Additional Guidelines:
Include:
A categorized summary of the page's SEO performance (e.g., metadata, technical SEO, content).
A prioritized list of recommended actions.
Visual examples or detailed explanations, when applicable.
Proactively address multiple detected issues with follow-up questions:
"The page has several critical issues, including missing Open Graph tags and a non-canonical URL. Would you like me to prioritize recommendations for social media or canonicalization first?"
Conversation starters
User-Agent: Googlebot, URL: https://example.com
Analyze the SEO details for https://example.com using Googlebot.
Analyze the page using the Samsung Galaxy S22 user-agent.
What metadata is available for https://example.com with Chrome?
Capabilities
Web Search
Code Interpreter & Data Analysis
На этом этапе ваша конфигурация должна выглядеть примерно так:
Заполненные конфигурации GPT
Заполненные конфигурации GPT (скриншот из ChatGPT, май 2025 г.)
Прежде чем перейти к созданию нового действия , просмотрите все эти поля и проверьте, правильно ли вы их заполнили.
Перейдите в раздел «Аутентификация» и выберите «Нет» .
Аутентификация GPTАутентификация GPT (скриншот из ChatGPT, май 2025 г.)
Добавьте следующую кодировку действия ChatGPT в поле Schema, но не забудьте изменить поле servers > url на свой собственный URL. Я назову его «https://CHANGETOYOURURL.com/», чтобы вам было легче его найти.
{
"openapi": "3.1.0",
"info": {
"title": "Enhanced SEO Analysis and Audit API",
"description": "Fetch SEO data for analysis. Use the returned data to generate actionable SEO recommendations using AI or experts.",
"version": "1.2.0"
},
"servers": [
{
"url": "https://CHANGETOYOURURL.com/",
"description": "Base URL for Enhanced SEO Analysis API"
}
],
"paths": {
"/": {
"get": {
"operationId": "fetchAndAuditSEOData",
"summary": "Fetch and Audit SEO Data",
"description": "Retrieve SEO analysis data using a user-agent and URL and perform a basic SEO audit.",
"parameters": [
{
"name": "user-agent",
"in": "query",
"description": "The user-agent for the request.",
"required": true,
"schema": {
"type": "string",
"enum": ["chrome", "googlebot", "iphone13pmax", "samsung5g"]
}
},
{
"name": "url",
"in": "query",
"description": "The URL of the webpage to analyze.",
"required": true,
"schema": {
"type": "string",
"format": "uri"
}
}
],
"responses": {
"200": {
"description": "Successful response with audit results",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"metadata": {
"type": "object",
"properties": {
"title": { "type": "string" },
"metaDescription": { "type": "string" },
"canonical": { "type": "string" }
}
},
"redirectChain": {
"type": "array",
"items": {
"type": "object",
"properties": {
"url": { "type": "string" },
"status": { "type": "integer" }
}
}
},
"openGraph": {
"type": "object",
"properties": {
"ogTitle": { "type": "string" },
"ogDescription": { "type": "string" },
"ogImage": { "type": "string" }
}
},
"twitterCards": {
"type": "object",
"properties": {
"twitterTitle": { "type": "string" },
"twitterDescription": { "type": "string" },
"twitterImage": { "type": "string" }
}
},
"sitemaps": {
"type": "array",
"items": { "type": "string" }
},
"robotsTxt": {
"type": "string"
},
"audit": {
"type": "object",
"properties": {
"issues": {
"type": "array",
"items": { "type": "string" }
},
"recommendations": {
"type": "array",
"items": { "type": "string" }
}
}
},
"auditSummary": {
"type": "array",
"items": {
"type": "string"
}
},
"nextSteps": {
"type": "array",
"items": {
"type": "string"
}
}
}
}
}
}
},
"400": {
"description": "Bad Request",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"error": { "type": "string" }
}
}
}
}
}
}
}
}
}
}
Вы должны увидеть его в разделе «Доступные действия: fetchAndAuditSEOData».
В разделе «Политика конфиденциальности» добавьте ссылку на свою политику конфиденциальности.
Наконец, нажмите « Создать » в правом верхнем углу и следуйте инструкциям.
Теперь вы можете просмотреть свой GPT; он будет похож на этот аудит GPT на странице SEO .
Тестирование вашего GPT и ознакомление с вашими возможностями
Вы проделали большой путь с собственным GPT, и пришло время протестировать его.
Нажмите на вторую плитку «Анализ данных SEO». По умолчанию будет выбран example.com, но вы можете указать ему протестировать понравившийся вам URL.
Давайте попробуем: netflix.com, указав «Использовать netflix.com в качестве URL-адреса».
Пример
Скриншот из ChatGPT, май 2025 г.
Теперь вы можете поэкспериментировать с любым из доступных вариантов GPT, чтобы увидеть, как все работает вместе.
Дальнейшая настройка вашего GPT
Возможно, вы захотите дополнительно настроить свой GPT, вернувшись туда, где вы его создали, и обновив несколько вещей.
Обновите темы для начала разговора, чтобы изменить:
Пользовательские агенты.
Отредактируйте инструкции, чтобы они лучше соответствовали вашим потребностям, добавив триггеры и ответы.
Если хотите, перейдите в кодировку вашего воркера и добавьте «const userAgents», чтобы добавить больше пользовательских агентов в список.
Теперь вы можете перейти к своему пользовательскому агенту GPT и просто указать ему, какую страницу сканировать следующей.
Это легко сделать, указав что-то вроде этого: «Измените URL-адрес на THEDESIREDURL», и ваш агент начнет работать за вас.
В итоге
Этот настраиваемый агент GPT — всего лишь один пример того, как объединение ChatGPT с Cloudflare Workers может оптимизировать основные задачи SEO.
Поэкспериментируйте с Агентом и измените его в соответствии со своими потребностями.
ИИ способен помочь во многих задачах, и он здесь, чтобы остаться. Таким образом, использование этой технологии в качестве помощника и эффективного инструмента имеет возможности помочь SEO-специалистам стать более эффективными в масштабе.
Комментарии