Eine Marketing-Technologie-Abteilung, die für vierzig Kundenseiten oder ein eigenes Website-Portfolio laufend Rankings prüft, stößt bei den üblichen SaaS-Ranktrackern an eine Grenze, die nichts mit der Zahl der Keywords zu tun hat. Ahrefs, Semrush und vergleichbare Werkzeuge zählen zusätzlich die Zahl der Projekte, also der getrennt verwalteten Domains, und verlangen für jede weitere Domain einen höheren Tarif. Ein Portfolio aus vierzig Websites landet damit oft in einem Tarif, dessen Keyword-Kontingent weit über dem tatsächlichen Bedarf liegt, nur weil die Projektzahl den Ausschlag gibt.
DataForSEO ist ein API-Anbieter für SEO-Rohdaten und verkauft dieselben Suchergebnisdaten ohne dieses Limit: abgerechnet wird pro Abfrage, unabhängig davon, wie viele Domains dahinterstehen. Wer eine eigene, kleine Pipeline gegen diese API baut, ruft für jedes Keyword und jede zu überwachende Domain eine Position ab, speichert das Ergebnis in einer eigenen Datenbank und baut das Reporting selbst. Der Aufwand dafür ist real. Er lohnt sich vor allem dort, wo mehrere Websites gleichzeitig überwacht werden und ein einheitlicher Bericht über alle Domains gebraucht wird, den kein SaaS-Dashboard von Haus aus liefert.
Systemvoraussetzungen
| Komponente | Anforderung |
|---|---|
| DataForSEO-Konto | Registrierung im DataForSEO-Dashboard, Mindesteinzahlung 50 US-Dollar, 1 US-Dollar Startguthaben zum Testen |
| API-Zugangsdaten | Login und Passwort aus dem Reiter API Access im Dashboard, nicht identisch mit dem Login-Passwort des Accounts |
| Authentifizierung | HTTP Basic Auth, Login und Passwort Base64-kodiert im Authorization-Header, niemals als URL-Parameter |
| Laufzeit für das Pipeline-Skript | Node.js in einer aktuellen LTS-Version oder eine gleichwertige serverseitige Laufzeit |
| Öffentlich erreichbarer Postback-Endpunkt | HTTPS-Adresse, die eine gzip-komprimierte POST-Anfrage entgegennimmt und innerhalb von 10 Sekunden mit HTTP 200 antwortet |
| Eigene Datenbank | PostgreSQL oder vergleichbar, mit einer Tabelle für Keyword, Domain, Position und Prüfzeitpunkt |
| Zeitsteuerung für den Lauf | Cron-Job oder Serverless-Funktion, die täglich oder wöchentlich neue Tasks einreicht |
Systemarchitektur
flowchart TD
A[Cron Job startet den taeglichen Lauf] --> B[Task Post schickt bis zu 100 Keywords je Aufruf]
B --> C[DataForSEO Standardqueue nimmt die Tasks an]
C --> D{Zustellung per Postback oder per Abfrage}
D -->|Postback| E[DataForSEO sendet das Ergebnis per POST an den eigenen Endpunkt]
D -->|Polling| F[Tasks Ready wird alle paar Minuten abgefragt]
F --> G[Task Get holt das Ergebnis je fertiger ID ab]
E --> H[Ergebnis wird entpackt und geparst]
G --> H
H --> I[Position und SERP Merkmale werden herausgelesen]
I --> J[Eigene Datenbank speichert eine Zeile je Keyword Domain und Zeitpunkt]
J --> K[Reporting Abfrage vergleicht die aktuelle mit der vorherigen Position]
K --> L[Bericht zeigt die Veraenderung ueber das gesamte Portfolio]
Der Lauf beginnt mit einem Cron-Job, der für jede zu prüfende Kombination aus Keyword und Domain einen Task an die Standardqueue von DataForSEO übergibt, in einem einzigen Aufruf mit bis zu 100 Tasks gleichzeitig. Für die Zustellung gibt es zwei Wege. Beim Postback schickt DataForSEO das fertige Ergebnis von sich aus per POST an eine selbst betriebene Adresse, sobald der Task fertig ist, eine Vorgehensweise, die als Webhook bekannt ist. Beim Polling fragt die eigene Pipeline stattdessen in Abständen die Liste tasks_ready ab und holt sich jedes fertige Ergebnis aktiv über einen zweiten Aufruf. Beide Wege liefern dieselben Felder: die Position in den organischen Treffern, die gefundene URL und die SERP-Merkmale, also zusätzliche Elemente wie Featured Snippets oder die Frage-Box People Also Ask, die auf der Ergebnisseite neben der reinen Trefferliste erscheinen. Die eigene Datenbank speichert für jede Prüfung eine Zeile mit Keyword, Domain, Position und Zeitstempel. Eine Reporting-Abfrage vergleicht anschließend den aktuellen mit dem vorherigen Stand und macht daraus die eigentliche Überwachung: nicht die einzelne Abfrage zeigt den Wert, sondern der Verlauf über die Zeit.
Was kostet eigenes Rank-Tracking gegenüber einem SaaS-Abo?
Eigenes Rank-Tracking über die DataForSEO-API kostet für ein Portfolio mit 2.000 täglich geprüften Keywords rund 36 US-Dollar im Monat, unabhängig davon, ob diese Keywords zu vier oder zu vierzig Domains gehören. Ein vergleichbares Ahrefs-Abo verlangt für dieselbe Keyword-Menge mindestens den Standard-Tarif, der aber nur 20 Projekte, also getrennt verwaltete Domains, erlaubt. Bei vierzig Websites reicht dieser Tarif nicht, und der nächsthöhere Advanced-Tarif kostet monatlich mehr als das Zehnfache der eigenen Pipeline, obwohl dessen Keyword-Kontingent von 5.000 zu einem Großteil ungenutzt bliebe.
| Lösung | Preis pro Monat | Projektlimit | Keyword-Kontingent |
|---|---|---|---|
| DataForSEO Task-API, Standardqueue | rund 36 US-Dollar bei 2.000 täglichen Prüfungen | kein Limit | pro Abfrage abgerechnet, kein festes Kontingent |
| Ahrefs Lite | 119 Euro | 5 Projekte | 750 Keywords |
| Ahrefs Standard | 229 Euro | 20 Projekte | 2.000 Keywords |
| Ahrefs Advanced | 419 Euro | 50 Projekte | 5.000 Keywords |
DataForSEO rechnet weltweit einheitlich in US-Dollar ab, Ahrefs zeigt seine Tarife in der Währung der jeweiligen Abrechnungsregion, hier in Euro. Der genaue Wechselkurs ändert daran wenig: Selbst mit großzügigem Aufschlag bleibt die eigene Pipeline für ein Portfolio dieser Größenordnung um ein Vielfaches günstiger als der passende SaaS-Tarif. Der Vergleich hat aber eine Grenze. In den 36 US-Dollar steckt nur die reine Datenabfrage, nicht die Zeit für Aufbau und Pflege der Pipeline, nicht die Datenbank und nicht das Reporting, das bei Ahrefs bereits fertig im Dashboard liegt. Für eine einzelne Website mit einer Handvoll Keywords ist der Aufwand für eine eigene Pipeline größer als ihr Nutzen, dort bleibt ein SaaS-Abo die einfachere Lösung, weil dort Keyword-Recherche, Backlink-Daten und Wettbewerbsanalyse gleich mit dabei sind.
Ein weiterer Hebel für die Kostenkontrolle liegt im Feld priority. Der Wert 1, die normale Standardqueue, kostet 0,0006 US-Dollar je geprüftem Keyword und liefert das Ergebnis im Schnitt nach etwa fünf Minuten. Der Wert 2 schaltet auf die Priorityqueue um, verdoppelt den Preis auf 0,0012 US-Dollar und drückt die Wartezeit auf etwa eine Minute. Für ein tägliches Portfolio-Monitoring, bei dem niemand live vor dem Bildschirm auf das Ergebnis wartet, bleibt priority 1 die richtige Wahl für den gesamten Lauf. Der Live-Endpunkt der SERP-API, der ein Ergebnis synchron in etwa sechs Sekunden liefert, kostet mit 0,002 US-Dollar je Keyword mehr als das Dreifache der Standardqueue und eignet sich eher für einen einzelnen Check im Frontend als für ein Portfolio mit tausenden Keywords.
Schritt-für-Schritt-Umsetzung
- Zugangsdaten aus dem DataForSEO-Dashboard in eine Umgebungsvariable eintragen.
- Für jede zu prüfende Kombination aus Keyword und Domain einen Task einreichen.
- Ergebnis per Postback oder per Abfrage abholen und in der eigenen Datenbank ablegen.
- Über die gespeicherte Zeitreihe die Positionsveränderung je Keyword und Domain berechnen.
Task per API-Aufruf einreichen
Ein Task für ein einzelnes Keyword geht als POST-Aufruf an den Endpunkt task_post, mit dem Keyword, dem Standortcode, der Sprache und, falls gewünscht, der Adresse für den Postback im Anfragekörper. Der Standortcode 2276 steht für Deutschland, das Feld tag nimmt eine selbst gewählte Kennung auf, die im Ergebnis unverändert zurückkommt und die Zuordnung zur richtigen Domain im eigenen System erlaubt.
curl -s -u "$DATAFORSEO_API" \
-H "Content-Type: application/json" \
-X POST "https://api.dataforseo.com/v3/serp/google/organic/task_post" \
-d '[{
"keyword": "hundefutter testsieger",
"location_code": 2276,
"language_code": "de",
"priority": 1,
"postback_url": "https://monitoring.example.com/api/dataforseo-callback",
"postback_data": "regular",
"tag": "kunde-a_hundefutter-testsieger"
}]'
Dieselbe Anfrage aus einem Node.js-Skript heraus baut den Authorization-Header aus Login und Passwort und prüft den Antwortcode, bevor sie die Task-ID für die spätere Zuordnung speichert:
const auth = "Basic " + Buffer.from(process.env.DATAFORSEO_API).toString("base64");
async function taskEinreichen(keyword, domain, tag) {
const response = await fetch(
"https://api.dataforseo.com/v3/serp/google/organic/task_post",
{
method: "POST",
headers: {
Authorization: auth,
"Content-Type": "application/json",
},
body: JSON.stringify([
{
keyword,
location_code: 2276,
language_code: "de",
priority: 1,
postback_url: "https://monitoring.example.com/api/dataforseo-callback",
postback_data: "regular",
tag,
},
]),
}
);
const payload = await response.json();
if (payload.status_code !== 20000) {
throw new Error("DataForSEO lehnte den Auftrag ab: " + payload.status_message);
}
return payload.tasks[0].id;
}
Ergebnis per Postback oder durch Abfrage abholen
Ist ein Task fertig, schickt DataForSEO das Ergebnis unaufgefordert an die im Postback-URL genannte Adresse, gzip-komprimiert und als POST-Anfrage. Der eigene Endpunkt muss die Anfrage entpacken und innerhalb von 10 Sekunden mit HTTP 200 antworten, sonst bricht DataForSEO die Zustellung ab und legt den Task stattdessen in die Liste tasks_ready.
app.post("/api/dataforseo-callback", express.json({ limit: "5mb" }), async (req, res) => {
const task = req.body.tasks && req.body.tasks[0];
if (!task || task.status_code !== 20000) {
res.sendStatus(200);
return;
}
const items = (task.result && task.result[0] && task.result[0].items) || [];
const eigenerTreffer = items.find(
(item) => item.type === "organic" && item.domain === "beispiel-shop.de"
);
await positionSpeichern({
keyword: task.data.keyword,
domain: "beispiel-shop.de",
position: eigenerTreffer ? eigenerTreffer.rank_absolute : null,
geprueftAm: new Date(),
});
res.sendStatus(200);
});
Wer keinen öffentlich erreichbaren Endpunkt betreiben will oder kann, fragt stattdessen aktiv nach: Die Liste tasks_ready nennt bis zu 1.000 fertige, noch nicht abgeholte Task-IDs pro Aufruf und kostet nichts, solange nur diese Liste abgefragt wird. Zu jeder ID liefert sie direkt den passenden Pfad zum Abholen des Ergebnisses.
async function offeneErgebnisseAbholen() {
const res = await fetch(
"https://api.dataforseo.com/v3/serp/google/organic/tasks_ready",
{ headers: { Authorization: auth } }
);
const payload = await res.json();
const fertigeTasks = (payload.tasks[0] && payload.tasks[0].result) || [];
for (const eintrag of fertigeTasks) {
const ergebnis = await fetch(
"https://api.dataforseo.com" + eintrag.endpoint_regular,
{ headers: { Authorization: auth } }
);
const daten = await ergebnis.json();
// daten.tasks[0].result[0].items enthaelt dieselben Felder wie beim Postback
}
}
Positionen in einer eigenen Datenbank ablegen
Die Tabelle für die Zeitreihe braucht nur vier Felder: das geprüfte Keyword, die überwachte Domain, die gefundene Position und den Prüfzeitpunkt. Eine fünfte Spalte für gefundene SERP-Merkmale lohnt sich, weil ein Ranking auf Position drei neben einem Featured Snippet des Wettbewerbers weniger wert ist als dieselbe Position ohne ein solches Element davor.
CREATE TABLE keyword_positionen (
id BIGSERIAL PRIMARY KEY,
keyword TEXT NOT NULL,
domain TEXT NOT NULL,
position INTEGER,
serp_merkmale TEXT[],
geprueft_am TIMESTAMPTZ NOT NULL DEFAULT now()
);
Die eigentliche Überwachung entsteht erst aus dem Vergleich zweier Zeilen. Eine Abfrage, die den heutigen mit dem gestrigen Stand je Keyword und Domain verbindet, macht aus der reinen Momentaufnahme eine Bewegung:
SELECT
heute.keyword,
heute.domain,
heute.position AS position_heute,
gestern.position AS position_gestern,
heute.position - gestern.position AS veraenderung
FROM keyword_positionen heute
JOIN keyword_positionen gestern
ON heute.keyword = gestern.keyword
AND heute.domain = gestern.domain
AND gestern.geprueft_am::date = heute.geprueft_am::date - interval '1 day'
WHERE heute.geprueft_am::date = current_date;
Weil alle Domains des Portfolios in derselben Tabelle liegen, lässt sich dieselbe Abfrage ohne Änderung auf eine einzelne Website oder auf das gesamte Portfolio anwenden, nur die WHERE-Bedingung wechselt. Genau diese Übersicht über mehrere Domains hinweg ist der Teil, den ein SaaS-Dashboard mit getrennten Projekten nur mit Zusatzaufwand oder gar nicht liefert.
Häufige Fehlerquellen
- HTTP 401 und Statuscode 40100 bei jedem Aufruf: Login und Passwort stehen falsch im Authorization-Header, meist weil beide unkodiert oder als URL-Parameter mitgeschickt wurden. Basic Auth erwartet die Kombination „login:password“ Base64-kodiert im Header, niemals in der URL.
- Statuscode 40200, Payment Required: Das Guthaben ist aufgebraucht. Der Lauf sollte in diesem Fall abbrechen und eine Meldung auslösen, nicht automatisch erneut versuchen, weil sich am fehlenden Guthaben durch einen Retry nichts ändert.
- Statuscode 40602, Task In Queue, beim Abholen: Der Task wurde abgefragt, bevor er fertig ist. Die Standardqueue braucht im Schnitt rund fünf Minuten; wer sofort nach dem Einreichen abfragt, bekommt diesen Status statt eines Ergebnisses und sollte über tasks_ready erneut abfragen statt den Task für fehlgeschlagen zu halten.
- Postback kommt leer oder unlesbar an: Zwei Ursachen sind wahrscheinlich. Entweder hat der eigene Endpunkt nicht innerhalb von 10 Sekunden mit HTTP 200 geantwortet, wodurch DataForSEO die Zustellung abbricht und den Task stattdessen in tasks_ready einreiht, oder der Endpunkt hat die eingehende Anfrage nicht als gzip entpackt, bevor er sie als JSON parsen wollte.
- Statuscode 40202, Rate-Limit überschritten: Mehr als 2.000 Aufrufe pro Minute oder mehr als 30 gleichzeitige Anfragen. Die Behebung liegt selten in mehr Geduld, sondern im Bündeln: Ein POST-Aufruf darf bis zu 100 Tasks gleichzeitig enthalten, einzelne Aufrufe pro Keyword verbrauchen das Limit unnötig schnell.
- Statuscode 40403, Results Expired: Das Ergebnis eines Tasks ist älter als 30 Tage und lässt sich nicht mehr abrufen. DataForSEO ist kein Archiv; Positionsdaten gehören sofort nach dem Abholen in die eigene Datenbank, nicht erst bei Bedarf Wochen später.
Häufig gestellte Fragen
Was kostet DataForSEO im Vergleich zu einem SaaS-Ranktracker?
DataForSEO kostet für 2.000 täglich geprüfte Keywords über die Task-API in der Standardqueue rund 36 US-Dollar im Monat, unabhängig von der Zahl der überwachten Domains. Ein Ahrefs-Tarif mit derselben Keyword-Menge liegt je nach benötigter Projektzahl zwischen 229 und 419 Euro im Monat, weil Ahrefs zusätzlich die Zahl der getrennt verwalteten Domains begrenzt. In den 36 US-Dollar steckt allerdings nur die reine Datenabfrage, nicht die Zeit für Pipeline und Reporting.
Wie unterscheiden sich die Live-API und die Task-API von DataForSEO?
Die Live-API liefert ein Ergebnis synchron in rund sechs Sekunden und kostet 0,002 US-Dollar je Keyword, während die Task-API einen Auftrag in eine Warteschlange stellt und das Ergebnis nach etwa fünf Minuten für 0,0006 US-Dollar je Keyword liefert. Die Task-API erlaubt außerdem bis zu 100 Keywords in einem einzigen Aufruf, die Live-API genau eines. Für ein tägliches Portfolio-Monitoring ist die Task-API die passende Wahl, die Live-API eignet sich eher für einen einzelnen Check, dessen Ergebnis sofort im Frontend erscheinen soll.
Was passiert, wenn ein DataForSEO-API-Schlüssel ungültig ist oder das Guthaben leer ist?
Ein ungültiger DataForSEO-API-Schlüssel führt zu HTTP 401 und dem internen Statuscode 40100, ein leeres Guthaben zu Statuscode 40200 mit der Meldung Payment Required. Beide Fehler kommen sofort bei jedem Aufruf zurück und lassen sich nicht durch Wiederholen beheben, weil sich weder Zugangsdaten noch Kontostand dadurch ändern. Die richtige Reaktion einer Pipeline ist, den Lauf sofort abzubrechen und eine Meldung auszulösen statt stumm weiterzumachen.
Lohnt sich eine eigene DataForSEO-Pipeline auch für eine einzelne Website?
Für eine einzelne Website lohnt sich eine eigene DataForSEO-Pipeline in den meisten Fällen nicht. Ein SaaS-Ranktracker bringt für eine einzelne Domain bereits Keyword-Recherche, Backlink-Daten, Wettbewerbsanalyse und ein fertiges Dashboard mit, während eine eigene Pipeline zusätzlich zur Datenabfrage noch Speicherung und Reporting selbst bauen muss. Der Kostenvorteil der API zeigt sich erst dort, wo mehrere Domains gleichzeitig überwacht werden und ein SaaS-Tarif durch sein Projektlimit unverhältnismäßig teuer wird.