API Platformu
Teknik SEO API
Herhangi bir URL üzerinde kapsamlı teknik SEO denetimi yapın.
Herhangi bir URL üzerinde kapsamlı teknik SEO denetimi yapın. Meta etiketler, başlıklar, bağlantılar, görseller, içerik, URL yapısı ve sosyal etiketler olmak üzere 7 kategoride 27 kontrol — puanlı rapor ve aksiyona dönüştürülebilir sorunlar döndürür.
Ürün sayfası: Teknik SEO API.
Kimlik Doğrulama
Tüm istekler başlık tabanlı kimlik doğrulama gerektirir. Her istekte API kimlik bilgilerinizi ekleyin.
| Header | Type | Açıklama |
|---|---|---|
SEMUST-API-USER | string | API kullanıcınızın kullanıcı adı |
SEMUST-API-PASSWORD | string | API kullanıcınızın şifresi |
API kimlik bilgilerini API Erişim sayfasında doğrulayabilirsiniz.
SEMUST-API-USER: your_username
SEMUST-API-PASSWORD: your_passwordRequest Parameters
Aşağıdaki parametrelerle bir application/json gövdesi gönderin:
Body
urlstringrequiredDenetlenecek URL. http:// veya https:// ile başlamalıdır (ör: "https://example.com").
render_jsbooleandefault: falseTrue olduğunda, denetim öncesi JavaScript'i işlemek için headless tarayıcı kullanır. SPA ve JS-ağırlıklı sayfalar için kullanın. Maliyeti artırabilir.
proxy_countrystringdefault: nullProxy seçimi için ISO 3166-1 alpha-2 ülke kodu (ör: "US", "TR", "DE"). Hedef site coğrafi engelleme yapıyorsa kullanın.
JavaScript İşleme
render_js etkinleştirildiğinde headless tarayıcı kullanılır, bu işlem süresini ve maliyeti artırır. Yalnızca içeriğini göstermek için JavaScript gerektiren sayfalar (SPA, React/Vue uygulamaları) için etkinleştirin.
{
"url": "https://example.com",
"render_js": false,
"proxy_country": "US"
}Kod Örnekleri
Farklı programlama dillerinde Teknik SEO denetimi nasıl çalıştırılacağını gösteren örnekler.
curl -X POST https://data.semust.com/v1/technical-seo \
-H "Content-Type: application/json" \
-H "SEMUST-API-USER: your_username" \
-H "SEMUST-API-PASSWORD: your_password" \
-d '{
"url": "https://example.com",
"render_js": false
}'import requests
import json
response = requests.post(
"https://data.semust.com/v1/technical-seo",
headers={
"SEMUST-API-USER": "your_username",
"SEMUST-API-PASSWORD": "your_password",
},
json={
"url": "https://example.com",
"render_js": False,
},
)
if response.status_code == 200:
data = response.json()
summary = data.get("summary", {})
print(f"Score: {summary.get('score', 0)}/100")
print(f"Issues: {summary.get('total_issues', 0)} total "
f"({summary.get('critical_issues', 0)} critical, "
f"{summary.get('warning_issues', 0)} warning, "
f"{summary.get('notice_issues', 0)} notice)")
# Print failed audits by category
for category, audits in data.get("audit_results", {}).items():
issues = {k: v for k, v in audits.items() if v and v.get("status") == "fail"}
if issues:
print(f"\n[{category.upper()}]")
for name, details in issues.items():
print(f" - {name}: {details.get('issue', '')}")
else:
print(f"Error [{response.status_code}]: {response.text}")const response = await fetch("https://data.semust.com/v1/technical-seo", {
method: "POST",
headers: {
"Content-Type": "application/json",
"SEMUST-API-USER": "your_username",
"SEMUST-API-PASSWORD": "your_password",
},
body: JSON.stringify({
url: "https://example.com",
render_js: false,
}),
});
if (response.ok) {
const data = await response.json();
const { summary } = data;
console.log(`Score: ${summary.score}/100`);
console.log(`Issues: ${summary.total_issues} total`);
// Print failed audits
for (const [category, audits] of Object.entries(data.audit_results)) {
for (const [name, result] of Object.entries(audits)) {
if (result?.status === "fail") {
console.log(`[${category}] ${name}: ${result.issue}`);
}
}
}
} else {
const text = await response.text();
console.error(`Error [${response.status}]: ${text}`);
}package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
)
func main() {
payload := map[string]interface{}{
"url": "https://example.com",
"render_js": false,
}
body, _ := json.Marshal(payload)
req, _ := http.NewRequest("POST",
"https://data.semust.com/v1/technical-seo",
bytes.NewBuffer(body))
req.Header.Set("Content-Type", "application/json")
req.Header.Set("SEMUST-API-USER", "your_username")
req.Header.Set("SEMUST-API-PASSWORD", "your_password")
resp, err := (&http.Client{}).Do(req)
if err != nil {
fmt.Printf("Request failed: %v\n", err)
return
}
defer resp.Body.Close()
respBody, _ := io.ReadAll(resp.Body)
if resp.StatusCode == 200 {
var data map[string]interface{}
json.Unmarshal(respBody, &data)
if summary, ok := data["summary"].(map[string]interface{}); ok {
fmt.Printf("Score: %v/100\n", summary["score"])
fmt.Printf("Issues: %v total\n", summary["total_issues"])
}
} else {
fmt.Printf("Error %d: %s\n",
resp.StatusCode, string(respBody))
}
}<?php
$payload = json_encode([
"url" => "https://example.com",
"render_js" => false,
]);
$ch = curl_init("https://data.semust.com/v1/technical-seo");
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
"Content-Type: application/json",
"SEMUST-API-USER: your_username",
"SEMUST-API-PASSWORD: your_password",
]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode === 200) {
$data = json_decode($response, true);
$summary = $data["summary"] ?? [];
echo "Score: " . ($summary["score"] ?? 0) . "/100\n";
echo "Issues: " . ($summary["total_issues"] ?? 0) . " total\n";
} else {
echo "Error [{$httpCode}]: {$response}\n";
}Response
Kategorize edilmiş denetim sonuçları ve özet puan içeren bir JSON nesnesi döndürür.
Root Response Fields
| Alan | Type | Açıklama |
|---|---|---|
success | boolean | Başarılı yanıtta her zaman true |
url | string | Denetlenen URL |
cost | float | Bu istek için düşülen kredi (USD) |
audit_results | object | Kategoriye göre gruplandırılmış denetim sonuçları (meta, başlıklar, bağlantılar, görseller, içerik, url_analizi, sosyal) |
summary | object | Toplu istatistikler: toplam kontrol, ciddiyet seviyesine göre sorunlar ve genel puan |
Audit Result Structure
Her kategorideki denetim aynı yapıyı izler:
| Alan | Type | Açıklama |
|---|---|---|
status | string | "pass", "fail" veya "error" — denetim sonucu |
severity | string | "critical", "warning" veya "notice" — etki seviyesi |
issue | string | Sorun kodu tanımlayıcısı (yalnızca status "fail" olduğunda mevcut) |
data | object | Kontrole özgü ayrıntılı veriler (her denetime göre değişir) |
Summary Object Fields
| Alan | Type | Açıklama |
|---|---|---|
total_checks | integer | Yapılan toplam denetim sayısı |
passed_checks | integer | Geçen denetim sayısı |
total_issues | integer | Başarısız olan denetim sayısı |
critical_issues | integer | Kritik ciddiyet seviyesindeki başarısızlık sayısı |
warning_issues | integer | Uyarı ciddiyet seviyesindeki başarısızlık sayısı |
notice_issues | integer | Bilgi ciddiyet seviyesindeki başarısızlık sayısı |
score | integer | Genel puan (0-100) — geçen kontrollerin yüzdesi |
{
"success": true,
"url": "https://example.com",
"cost": 0.0012,
"audit_results": {
"meta": {
"title": {
"status": "fail",
"severity": "warning",
"issue": "long_title",
"data": { "title": "Very Long Page Title...", "length": 66 }
},
"meta_description": {
"status": "pass",
"severity": "warning",
"data": { "meta_description": "Page description...", "length": 93 }
},
"canonical_url": {
"status": "pass",
"severity": "warning",
"data": { "current_url": "https://example.com", "canonical_url": "https://example.com" }
},
"robots_noindex": { "status": "pass", "severity": "critical", "data": {} },
"viewport": {
"status": "pass",
"severity": "critical",
"data": { "content": "width=device-width, initial-scale=1" }
}
},
"headings": {
"missing_h1": {
"status": "pass",
"severity": "critical",
"data": { "h1_count": 1, "h1_text": "Welcome" }
},
"broken_heading_structure": {
"status": "fail",
"severity": "warning",
"issue": "broken_heading_structure",
"data": { "total_count": 12, "skipped_levels": 1 }
}
},
"images": {
"images_without_alt": { "status": "pass", "severity": "warning", "data": { "total_images": 10 } },
"missing_image_dimensions": {
"status": "fail",
"severity": "warning",
"issue": "missing_image_dimensions",
"data": { "total_images": 10, "count": 5 }
}
},
"content": {
"low_word_count": { "status": "pass", "severity": "warning", "data": { "word_count": 684 } },
"low_html_text_ratio": {
"status": "fail",
"severity": "warning",
"issue": "low_html_text_ratio",
"data": { "text_to_html_ratio": 8.08 }
}
}
},
"summary": {
"total_checks": 27,
"passed_checks": 23,
"total_issues": 4,
"critical_issues": 0,
"warning_issues": 4,
"notice_issues": 0,
"score": 85
}
}Audit Kontrolleri (27)
Meta Etiketler (8)
| Audit | Severity | Açıklama |
|---|---|---|
title | critical | Eksik, çok kısa (≤10 karakter) veya çok uzun (>60 karakter) title etiketi kontrolü |
meta_description | warning | Eksik, çok kısa (<50 karakter) veya çok uzun (>160 karakter) meta açıklama kontrolü |
canonical_url | warning | Eksik, birden fazla veya uyumsuz canonical URL kontrolü |
robots_noindex | critical | Robots veya googlebot meta etiketlerinde noindex direktifi algılama |
viewport | critical | Eksik veya geçersiz viewport meta etiketi kontrolü (width=device-width içermeli) |
missing_lang | warning | HTML etiketinin lang özniteliğine sahip olduğunu kontrol eder |
noindex_canonical_conflict | critical | Sayfada hem noindex hem canonical URL bulunması çakışmasını algılar |
hreflang | warning | Hreflang uygulamasını doğrular: dil kodları, x-default, kendi kendine referans etiketleri |
Başlıklar (4)
| Audit | Severity | Açıklama |
|---|---|---|
missing_h1 | critical | Sayfada en az bir H1 etiketi olduğunu kontrol eder |
multiple_h1_tags | warning | Sayfada tam olarak bir H1 etiketi olduğunu kontrol eder (birden fazla değil) |
duplicate_h1_tags | warning | H1 etiketlerinin aynı metne sahip olmadığını kontrol eder |
broken_heading_structure | warning | Başlık hiyerarşisini doğrular (H1→H2→H3), atlanan seviye veya boş başlık olmamalı |
Bağlantılar (5)
| Audit | Severity | Açıklama |
|---|---|---|
empty_anchor_text | warning | Bağlantı etiketlerinin metin içeriğine sahip olduğunu kontrol eder (boş değil) |
non_descriptive_anchors | notice | "Buraya tıklayın" veya "devamını oku" gibi açıklayıcı olmayan bağlantı metinlerini kontrol eder |
internal_links_nofollow | warning | İç bağlantıların nofollow özniteliğine sahip olmadığını kontrol eder |
too_many_internal_links | warning | Sayfada çok fazla iç bağlantı varsa uyarır (eşik değişir) |
too_many_external_links | warning | Sayfada çok fazla dış bağlantı varsa uyarır (eşik: 100) |
Görseller (2)
| Audit | Severity | Açıklama |
|---|---|---|
images_without_alt | warning | Görsellerin erişilebilirlik için alt özniteliğine sahip olduğunu kontrol eder |
missing_image_dimensions | warning | Görsellerin width ve height özniteliklerine sahip olduğunu kontrol eder (CLS'yi önler) |
İçerik (4)
| Audit | Severity | Açıklama |
|---|---|---|
low_word_count | warning | Ana içeriğin en az 200 kelime içerdiğini kontrol eder |
low_html_text_ratio | warning | Metin-HTML oranının %10'un üzerinde olduğunu kontrol eder |
lorem_ipsum | notice | Sayfa içeriğinde "lorem ipsum" yer tutucu metni algılar |
page_size | warning | HTML boyutunu (<3MB) ve DOM element sayısını (<1500) kontrol eder |
URL Analizi (2)
| Audit | Severity | Açıklama |
|---|---|---|
http_url | critical | URL'nin HTTP değil HTTPS kullandığını kontrol eder |
long_url | notice | URL 75 karakteri aşarsa uyarır |
Sosyal Etiketler (2)
| Audit | Severity | Açıklama |
|---|---|---|
open_graph | warning | Gerekli Open Graph etiketlerini kontrol eder: og:title, og:description, og:image, og:url, og:type |
twitter_card | notice | Twitter Card meta etiketlerini kontrol eder: card, title, description, image |
Hata Kodları
Tüm hatalar, insan tarafından okunabilir bir mesaj ve bir hata kodu içeren bir JSON nesnesi döndürür.
| HTTP | Kod | Anlamı |
|---|---|---|
| 400 | INVALID_REQUEST | İstek gövdesi hatalı biçimlendirilmiş veya gerekli alanlar eksik |
| 400 | URL_REQUIRED | url alanı zorunludur |
| 400 | INVALID_URL | Geçersiz URL formatı veya şeması — http:// veya https:// ile başlamalıdır |
| 401 | INVALID_API_KEY | Kimlik doğrulama başarısız — geçersiz kullanıcı adı veya şifre |
| 402 | INSUFFICIENT_CREDITS | Hesabınızda yeterli kredi yok |
| 500 | INTERNAL_ERROR | Bir iç sunucu hatası oluştu |
| 502 | AUDIT_FAILED | Hedef URL denetlenemedi |
| 502 | TARGET_BLOCKED | Hedef web sitesi otomatik erişimi aktif olarak engelliyor (403 Forbidden) |
| 502 | TARGET_UNREACHABLE | Hedefe ulaşılamıyor — DNS hatası, bağlantı zaman aşımı veya ağ hatası |
| 502 | SCRAPE_FAILED | Sayfanın alınmasında genel hata |
| 504 | TIMEOUT | İstek zaman aşımına uğradı (maksimum 2 dakika) |
{
"error": "Your account does not have enough credits",
"code": "INSUFFICIENT_CREDITS"
}Krediler & Rate Limits
Krediler
Her istek bakiyenizden kredi tüketir. Maliyet, render_js parametresine göre değişir (JS işleme daha pahalıdır). Başarısız istekler otomatik olarak iade edilir.
Rate Limits
İstekler, planınıza göre dakika başına ve gün başına sınırlara tabidir. Sınırların aşılması HTTP 429 döndürür.
