directory changes and restructuring
🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
606
custom-skills/_archive/seo-audit-agent/reference.md
Normal file
606
custom-skills/_archive/seo-audit-agent/reference.md
Normal file
@@ -0,0 +1,606 @@
|
||||
# OurDigital SEO Audit - API Reference
|
||||
|
||||
## Google Search Console API
|
||||
|
||||
### Authentication
|
||||
```python
|
||||
from google.oauth2 import service_account
|
||||
from googleapiclient.discovery import build
|
||||
|
||||
SCOPES = ['https://www.googleapis.com/auth/webmasters.readonly']
|
||||
credentials = service_account.Credentials.from_service_account_file(
|
||||
'service-account-key.json', scopes=SCOPES
|
||||
)
|
||||
service = build('searchconsole', 'v1', credentials=credentials)
|
||||
```
|
||||
|
||||
### Endpoints
|
||||
|
||||
#### Search Analytics
|
||||
```python
|
||||
# Get search performance data
|
||||
request = {
|
||||
'startDate': '2024-01-01',
|
||||
'endDate': '2024-12-31',
|
||||
'dimensions': ['query', 'page', 'country', 'device'],
|
||||
'rowLimit': 25000,
|
||||
'dimensionFilterGroups': [{
|
||||
'filters': [{
|
||||
'dimension': 'country',
|
||||
'expression': 'kor'
|
||||
}]
|
||||
}]
|
||||
}
|
||||
response = service.searchanalytics().query(
|
||||
siteUrl='sc-domain:example.com',
|
||||
body=request
|
||||
).execute()
|
||||
```
|
||||
|
||||
#### URL Inspection
|
||||
```python
|
||||
request = {
|
||||
'inspectionUrl': 'https://example.com/page',
|
||||
'siteUrl': 'sc-domain:example.com'
|
||||
}
|
||||
response = service.urlInspection().index().inspect(body=request).execute()
|
||||
```
|
||||
|
||||
#### Sitemaps
|
||||
```python
|
||||
# List sitemaps
|
||||
sitemaps = service.sitemaps().list(siteUrl='sc-domain:example.com').execute()
|
||||
|
||||
# Submit sitemap
|
||||
service.sitemaps().submit(
|
||||
siteUrl='sc-domain:example.com',
|
||||
feedpath='https://example.com/sitemap.xml'
|
||||
).execute()
|
||||
```
|
||||
|
||||
### Rate Limits
|
||||
- 1,200 queries per minute per project
|
||||
- 25,000 rows max per request
|
||||
|
||||
---
|
||||
|
||||
## PageSpeed Insights API
|
||||
|
||||
### Authentication
|
||||
```python
|
||||
import requests
|
||||
|
||||
API_KEY = 'your-api-key'
|
||||
BASE_URL = 'https://www.googleapis.com/pagespeedonline/v5/runPagespeed'
|
||||
```
|
||||
|
||||
### Request Parameters
|
||||
```python
|
||||
params = {
|
||||
'url': 'https://example.com',
|
||||
'key': API_KEY,
|
||||
'strategy': 'mobile', # or 'desktop'
|
||||
'category': ['performance', 'accessibility', 'best-practices', 'seo']
|
||||
}
|
||||
response = requests.get(BASE_URL, params=params)
|
||||
```
|
||||
|
||||
### Response Structure
|
||||
```json
|
||||
{
|
||||
"lighthouseResult": {
|
||||
"categories": {
|
||||
"performance": { "score": 0.85 },
|
||||
"seo": { "score": 0.92 }
|
||||
},
|
||||
"audits": {
|
||||
"largest-contentful-paint": {
|
||||
"numericValue": 2500,
|
||||
"displayValue": "2.5 s"
|
||||
},
|
||||
"cumulative-layout-shift": {
|
||||
"numericValue": 0.05
|
||||
},
|
||||
"total-blocking-time": {
|
||||
"numericValue": 150
|
||||
}
|
||||
}
|
||||
},
|
||||
"loadingExperience": {
|
||||
"metrics": {
|
||||
"LARGEST_CONTENTFUL_PAINT_MS": {
|
||||
"percentile": 2500,
|
||||
"category": "AVERAGE"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Core Web Vitals Thresholds
|
||||
|
||||
| Metric | Good | Needs Improvement | Poor |
|
||||
|--------|------|-------------------|------|
|
||||
| LCP | ≤ 2.5s | 2.5s - 4.0s | > 4.0s |
|
||||
| FID | ≤ 100ms | 100ms - 300ms | > 300ms |
|
||||
| CLS | ≤ 0.1 | 0.1 - 0.25 | > 0.25 |
|
||||
| INP | ≤ 200ms | 200ms - 500ms | > 500ms |
|
||||
| TTFB | ≤ 800ms | 800ms - 1800ms | > 1800ms |
|
||||
| FCP | ≤ 1.8s | 1.8s - 3.0s | > 3.0s |
|
||||
|
||||
### Rate Limits
|
||||
- 25,000 queries per day (free tier)
|
||||
- No per-minute limit
|
||||
|
||||
---
|
||||
|
||||
## Google Analytics 4 Data API
|
||||
|
||||
### Authentication
|
||||
```python
|
||||
from google.analytics.data_v1beta import BetaAnalyticsDataClient
|
||||
from google.analytics.data_v1beta.types import RunReportRequest
|
||||
|
||||
client = BetaAnalyticsDataClient()
|
||||
property_id = '123456789'
|
||||
```
|
||||
|
||||
### Common Reports
|
||||
|
||||
#### Traffic Overview
|
||||
```python
|
||||
request = RunReportRequest(
|
||||
property=f'properties/{property_id}',
|
||||
dimensions=[
|
||||
{'name': 'date'},
|
||||
{'name': 'sessionDefaultChannelGroup'}
|
||||
],
|
||||
metrics=[
|
||||
{'name': 'sessions'},
|
||||
{'name': 'totalUsers'},
|
||||
{'name': 'screenPageViews'},
|
||||
{'name': 'bounceRate'}
|
||||
],
|
||||
date_ranges=[{'start_date': '30daysAgo', 'end_date': 'today'}]
|
||||
)
|
||||
response = client.run_report(request)
|
||||
```
|
||||
|
||||
#### Landing Pages
|
||||
```python
|
||||
request = RunReportRequest(
|
||||
property=f'properties/{property_id}',
|
||||
dimensions=[{'name': 'landingPage'}],
|
||||
metrics=[
|
||||
{'name': 'sessions'},
|
||||
{'name': 'engagementRate'},
|
||||
{'name': 'conversions'}
|
||||
],
|
||||
date_ranges=[{'start_date': '30daysAgo', 'end_date': 'today'}],
|
||||
order_bys=[{'metric': {'metric_name': 'sessions'}, 'desc': True}],
|
||||
limit=100
|
||||
)
|
||||
```
|
||||
|
||||
### Useful Dimensions
|
||||
- `date`, `dateHour`
|
||||
- `sessionDefaultChannelGroup`
|
||||
- `landingPage`, `pagePath`
|
||||
- `deviceCategory`, `operatingSystem`
|
||||
- `country`, `city`
|
||||
- `sessionSource`, `sessionMedium`
|
||||
|
||||
### Useful Metrics
|
||||
- `sessions`, `totalUsers`, `newUsers`
|
||||
- `screenPageViews`, `engagementRate`
|
||||
- `averageSessionDuration`
|
||||
- `bounceRate`, `conversions`
|
||||
|
||||
---
|
||||
|
||||
## Google Trends API (pytrends)
|
||||
|
||||
### Installation
|
||||
```bash
|
||||
pip install pytrends
|
||||
```
|
||||
|
||||
### Usage
|
||||
```python
|
||||
from pytrends.request import TrendReq
|
||||
|
||||
pytrends = TrendReq(hl='ko-KR', tz=540)
|
||||
|
||||
# Interest over time
|
||||
pytrends.build_payload(['keyword1', 'keyword2'], timeframe='today 12-m', geo='KR')
|
||||
interest_df = pytrends.interest_over_time()
|
||||
|
||||
# Related queries
|
||||
related = pytrends.related_queries()
|
||||
|
||||
# Trending searches
|
||||
trending = pytrends.trending_searches(pn='south_korea')
|
||||
|
||||
# Suggestions
|
||||
suggestions = pytrends.suggestions('seo')
|
||||
```
|
||||
|
||||
### Rate Limits
|
||||
- No official limits, but implement delays (1-2 seconds between requests)
|
||||
- May trigger CAPTCHA with heavy usage
|
||||
|
||||
---
|
||||
|
||||
## Custom Search JSON API
|
||||
|
||||
### Authentication
|
||||
```python
|
||||
import requests
|
||||
|
||||
API_KEY = 'your-api-key'
|
||||
CX = 'your-search-engine-id' # Programmable Search Engine ID
|
||||
BASE_URL = 'https://www.googleapis.com/customsearch/v1'
|
||||
```
|
||||
|
||||
### Request
|
||||
```python
|
||||
params = {
|
||||
'key': API_KEY,
|
||||
'cx': CX,
|
||||
'q': 'search query',
|
||||
'num': 10, # 1-10
|
||||
'start': 1, # Pagination
|
||||
'gl': 'kr', # Country
|
||||
'hl': 'ko' # Language
|
||||
}
|
||||
response = requests.get(BASE_URL, params=params)
|
||||
```
|
||||
|
||||
### Response Structure
|
||||
```json
|
||||
{
|
||||
"searchInformation": {
|
||||
"totalResults": "12345",
|
||||
"searchTime": 0.5
|
||||
},
|
||||
"items": [
|
||||
{
|
||||
"title": "Page Title",
|
||||
"link": "https://example.com",
|
||||
"snippet": "Description...",
|
||||
"pagemap": {
|
||||
"metatags": [...],
|
||||
"cse_image": [...]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Rate Limits
|
||||
- 100 queries per day (free)
|
||||
- 10,000 queries per day ($5 per 1,000)
|
||||
|
||||
---
|
||||
|
||||
## Knowledge Graph Search API
|
||||
|
||||
### Request
|
||||
```python
|
||||
API_KEY = 'your-api-key'
|
||||
BASE_URL = 'https://kgsearch.googleapis.com/v1/entities:search'
|
||||
|
||||
params = {
|
||||
'key': API_KEY,
|
||||
'query': 'entity name',
|
||||
'types': 'Organization',
|
||||
'languages': 'ko',
|
||||
'limit': 10
|
||||
}
|
||||
response = requests.get(BASE_URL, params=params)
|
||||
```
|
||||
|
||||
### Response
|
||||
```json
|
||||
{
|
||||
"itemListElement": [
|
||||
{
|
||||
"result": {
|
||||
"@type": "EntitySearchResult",
|
||||
"name": "Entity Name",
|
||||
"description": "Description...",
|
||||
"@id": "kg:/m/entity_id",
|
||||
"detailedDescription": {
|
||||
"articleBody": "..."
|
||||
}
|
||||
},
|
||||
"resultScore": 1234.56
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Schema.org Reference
|
||||
|
||||
### JSON-LD Format
|
||||
```html
|
||||
<script type="application/ld+json">
|
||||
{
|
||||
"@context": "https://schema.org",
|
||||
"@type": "Organization",
|
||||
"name": "Company Name",
|
||||
"url": "https://example.com"
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
### Common Schema Types
|
||||
|
||||
#### Organization
|
||||
```json
|
||||
{
|
||||
"@context": "https://schema.org",
|
||||
"@type": "Organization",
|
||||
"name": "Company Name",
|
||||
"url": "https://example.com",
|
||||
"logo": "https://example.com/logo.png",
|
||||
"sameAs": [
|
||||
"https://facebook.com/company",
|
||||
"https://twitter.com/company"
|
||||
],
|
||||
"contactPoint": {
|
||||
"@type": "ContactPoint",
|
||||
"telephone": "+82-2-1234-5678",
|
||||
"contactType": "customer service"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### LocalBusiness
|
||||
```json
|
||||
{
|
||||
"@context": "https://schema.org",
|
||||
"@type": "LocalBusiness",
|
||||
"name": "Business Name",
|
||||
"address": {
|
||||
"@type": "PostalAddress",
|
||||
"streetAddress": "123 Street",
|
||||
"addressLocality": "Seoul",
|
||||
"addressRegion": "Seoul",
|
||||
"postalCode": "12345",
|
||||
"addressCountry": "KR"
|
||||
},
|
||||
"geo": {
|
||||
"@type": "GeoCoordinates",
|
||||
"latitude": 37.5665,
|
||||
"longitude": 126.9780
|
||||
},
|
||||
"openingHoursSpecification": [{
|
||||
"@type": "OpeningHoursSpecification",
|
||||
"dayOfWeek": ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"],
|
||||
"opens": "09:00",
|
||||
"closes": "18:00"
|
||||
}]
|
||||
}
|
||||
```
|
||||
|
||||
#### Article/BlogPosting
|
||||
```json
|
||||
{
|
||||
"@context": "https://schema.org",
|
||||
"@type": "Article",
|
||||
"headline": "Article Title",
|
||||
"author": {
|
||||
"@type": "Person",
|
||||
"name": "Author Name"
|
||||
},
|
||||
"datePublished": "2024-01-01",
|
||||
"dateModified": "2024-01-15",
|
||||
"image": "https://example.com/image.jpg",
|
||||
"publisher": {
|
||||
"@type": "Organization",
|
||||
"name": "Publisher Name",
|
||||
"logo": {
|
||||
"@type": "ImageObject",
|
||||
"url": "https://example.com/logo.png"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Product
|
||||
```json
|
||||
{
|
||||
"@context": "https://schema.org",
|
||||
"@type": "Product",
|
||||
"name": "Product Name",
|
||||
"image": "https://example.com/product.jpg",
|
||||
"description": "Product description",
|
||||
"brand": {
|
||||
"@type": "Brand",
|
||||
"name": "Brand Name"
|
||||
},
|
||||
"offers": {
|
||||
"@type": "Offer",
|
||||
"price": "29900",
|
||||
"priceCurrency": "KRW",
|
||||
"availability": "https://schema.org/InStock"
|
||||
},
|
||||
"aggregateRating": {
|
||||
"@type": "AggregateRating",
|
||||
"ratingValue": "4.5",
|
||||
"reviewCount": "100"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### FAQPage
|
||||
```json
|
||||
{
|
||||
"@context": "https://schema.org",
|
||||
"@type": "FAQPage",
|
||||
"mainEntity": [{
|
||||
"@type": "Question",
|
||||
"name": "Question text?",
|
||||
"acceptedAnswer": {
|
||||
"@type": "Answer",
|
||||
"text": "Answer text."
|
||||
}
|
||||
}]
|
||||
}
|
||||
```
|
||||
|
||||
#### BreadcrumbList
|
||||
```json
|
||||
{
|
||||
"@context": "https://schema.org",
|
||||
"@type": "BreadcrumbList",
|
||||
"itemListElement": [{
|
||||
"@type": "ListItem",
|
||||
"position": 1,
|
||||
"name": "Home",
|
||||
"item": "https://example.com/"
|
||||
}, {
|
||||
"@type": "ListItem",
|
||||
"position": 2,
|
||||
"name": "Category",
|
||||
"item": "https://example.com/category/"
|
||||
}]
|
||||
}
|
||||
```
|
||||
|
||||
#### WebSite (with SearchAction)
|
||||
```json
|
||||
{
|
||||
"@context": "https://schema.org",
|
||||
"@type": "WebSite",
|
||||
"name": "Site Name",
|
||||
"url": "https://example.com",
|
||||
"potentialAction": {
|
||||
"@type": "SearchAction",
|
||||
"target": {
|
||||
"@type": "EntryPoint",
|
||||
"urlTemplate": "https://example.com/search?q={search_term_string}"
|
||||
},
|
||||
"query-input": "required name=search_term_string"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## XML Sitemap Specification
|
||||
|
||||
### Format
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
||||
<url>
|
||||
<loc>https://example.com/page</loc>
|
||||
<lastmod>2024-01-15</lastmod>
|
||||
<changefreq>weekly</changefreq>
|
||||
<priority>0.8</priority>
|
||||
</url>
|
||||
</urlset>
|
||||
```
|
||||
|
||||
### Index Sitemap
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
||||
<sitemap>
|
||||
<loc>https://example.com/sitemap-posts.xml</loc>
|
||||
<lastmod>2024-01-15</lastmod>
|
||||
</sitemap>
|
||||
</sitemapindex>
|
||||
```
|
||||
|
||||
### Limits
|
||||
- 50,000 URLs max per sitemap
|
||||
- 50MB uncompressed max
|
||||
- Use index for larger sites
|
||||
|
||||
### Best Practices
|
||||
- Use absolute URLs
|
||||
- Include only canonical URLs
|
||||
- Keep lastmod accurate
|
||||
- Exclude noindex pages
|
||||
|
||||
---
|
||||
|
||||
## Robots.txt Reference
|
||||
|
||||
### Directives
|
||||
|
||||
```txt
|
||||
# Comments start with #
|
||||
User-agent: *
|
||||
Disallow: /admin/
|
||||
Disallow: /private/
|
||||
Allow: /public/
|
||||
|
||||
User-agent: Googlebot
|
||||
Disallow: /no-google/
|
||||
Crawl-delay: 1
|
||||
|
||||
Sitemap: https://example.com/sitemap.xml
|
||||
```
|
||||
|
||||
### Common User-agents
|
||||
- `*` - All bots
|
||||
- `Googlebot` - Google crawler
|
||||
- `Googlebot-Image` - Google Image crawler
|
||||
- `Bingbot` - Bing crawler
|
||||
- `Yandex` - Yandex crawler
|
||||
- `Baiduspider` - Baidu crawler
|
||||
|
||||
### Pattern Matching
|
||||
- `*` - Wildcard (any sequence)
|
||||
- `$` - End of URL
|
||||
- `/path/` - Directory
|
||||
- `/*.pdf$` - All PDFs
|
||||
|
||||
### Testing
|
||||
```python
|
||||
from urllib.robotparser import RobotFileParser
|
||||
|
||||
rp = RobotFileParser()
|
||||
rp.set_url("https://example.com/robots.txt")
|
||||
rp.read()
|
||||
|
||||
# Check if URL is allowed
|
||||
can_fetch = rp.can_fetch("Googlebot", "https://example.com/page")
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Error Handling
|
||||
|
||||
### HTTP Status Codes
|
||||
|
||||
| Code | Meaning | Action |
|
||||
|------|---------|--------|
|
||||
| 200 | OK | Process response |
|
||||
| 301/302 | Redirect | Follow or flag |
|
||||
| 400 | Bad Request | Check parameters |
|
||||
| 401 | Unauthorized | Check credentials |
|
||||
| 403 | Forbidden | Check permissions |
|
||||
| 404 | Not Found | Flag missing resource |
|
||||
| 429 | Rate Limited | Implement backoff |
|
||||
| 500 | Server Error | Retry with backoff |
|
||||
| 503 | Service Unavailable | Retry later |
|
||||
|
||||
### Retry Strategy
|
||||
```python
|
||||
from tenacity import retry, stop_after_attempt, wait_exponential
|
||||
|
||||
@retry(
|
||||
stop=stop_after_attempt(3),
|
||||
wait=wait_exponential(multiplier=1, min=2, max=10)
|
||||
)
|
||||
async def make_request(url):
|
||||
# Request logic
|
||||
pass
|
||||
```
|
||||
Reference in New Issue
Block a user