When Are Deeper Yahoo Results Worth Paying For?
Going deeper into Yahoo results earns its cost only if later pages add candidates useful for your task. Count new, relevant URLs at each requested depth; record duplicates and short deliveries separately. Set a stopping rule before you inspect the sample.
I founded Serpent API. This affiliated walkthrough uses its documented Deep search contract, with illustrative counts rather than an authenticated run of these Yahoo queries. The Yahoo API overview describes the available route.
Set a depth limit and a reason to go deeper
Use deep sampling when first-page results cannot answer the research question, such as finding lesser-known domains for a topic. Decide the maximum requested pages and a stopping rule before calling. Treat the output as a sample of results at a time and country, never a complete index dump.
Request a fixed total with num or pages, not both unless you know which takes precedence. The public contract says num takes precedence. Save the requested total, all returned organic rows, delivery information and a unique-URL count. Normalize tracking fragments conservatively, but keep meaningful search or product parameters. Preserve duplicate positions for audit even while reporting a first occurrence.
Save rows, duplicates and returned depth
Serpent’s Deep search can request up to 100 organic results and charges Web units by pages requested, up to ten pages. Depth is best-effort. Quick can also request multiple results but returns organic rows only; Deep is useful when you need richer blocks or a deliberate page-based sampling path.
| Field or control | Use in this workflow | Check before trusting it |
|---|---|---|
q, engine, country | Preserve the exact request identity. | Compare only samples with intended matching settings. |
results.organic[] | Read url, title and position from each usable row. | Validate array and row types; a position is an observed list location. |
num and returned count | Keep requested depth separate from usable rows. | Requested results are best-effort; never fill missing rows with invented values. |
delivery, meta.partialResults | Mark short or incomplete observations for review. | Inspect these before interpreting a missing URL as a change. |
Collect a bounded Yahoo sample
Install requests and set SERPENT_API_KEY in your local environment. This complete Python example shows the request and parsed-field handling for the workflow. It has been syntax-checked, but the sample query output has not been validated against an authenticated production response. Run it against your account before adopting it.
import os
from datetime import datetime, timezone
from urllib.parse import urlsplit, urlunsplit, parse_qsl, urlencode
import requests
BASE = "https://apiserpent.com"
KEY = os.environ["SERPENT_API_KEY"]
def snapshot(engine, query, country="us", num=10, deep=False):
endpoint = "/api/search" if deep else "/api/search/quick"
response = requests.get(
BASE + endpoint,
params={"engine": engine, "q": query, "country": country,
"num": num, "format": "full"},
headers={"X-API-Key": KEY}, timeout=55 if deep else 30)
response.raise_for_status()
data = response.json()
if data.get("success") is not True or not isinstance(data.get("results"), dict):
raise ValueError("No usable results object")
rows = data["results"].get("organic")
if not isinstance(rows, list):
raise ValueError("Organic rows are missing")
return {"observed_at": datetime.now(timezone.utc).isoformat(),
"query": query, "country": country, "engine": engine,
"requested": num, "organic": rows,
"delivery": data.get("delivery"),
"partial": (data.get("meta") or {}).get("partialResults")}
def normalized_url(raw):
if not isinstance(raw, str) or not raw.startswith(("https://", "http://")):
return None
parts = urlsplit(raw)
host = (parts.hostname or "").lower().removeprefix("www.")
path = parts.path.rstrip("/") or "/"
query = urlencode(sorted((k, v) for k, v in parse_qsl(parts.query)
if not k.lower().startswith("utm_")))
return urlunsplit((parts.scheme.lower(), host, path, query, ""))
sample = snapshot("yahoo", "independent running shoe stores",
country="us", num=30, deep=True)
first_seen = {}
duplicates = []
for row in sample["organic"]:
if not isinstance(row, dict):
continue
key = normalized_url(row.get("url"))
if not key:
continue
observation = {"position": row.get("position"),
"title": row.get("title"), "url": row.get("url")}
if key in first_seen:
duplicates.append({"key": key, "first": first_seen[key]["position"],
"again": observation["position"]})
else:
first_seen[key] = observation
print({"requested": sample["requested"], "returned": len(sample["organic"]),
"unique_urls": len(first_seen), "duplicates": duplicates,
"delivery": sample["delivery"], "partial": sample["partial"]})
How to read the output: If 30 were requested, 23 rows returned and 19 URLs were unique, report all three numbers. Those example numbers are a hypothetical worksheet, not a measured Yahoo run. Inspect rows without a valid URL separately rather than silently adding them to the unique count. Sample again at another time if the decision depends on a stable list.
What does the extra depth cost?
Price Deep by the pages requested, not by unique URLs returned. For a three-page Deep request at the documented Serpent Default rate of $0.60 per 1,000 Web units, the planning charge is 3 × $0.0006 = $0.0018. The 30-result code example should be checked against the account ledger for its actual requested-page charge; it is not priced from the 19 hypothetical unique URLs.
Serpent’s published pricing gives Web-category rates by account tier. The figures above use the documented Default rate as a dated planning example, not a measured invoice. Confirm your tier, optional features and actual charges in your account before scaling. A response with fewer rows does not by itself change the requested-page unit for Deep.
Compare depth options by useful output
| Option | Useful for | Published access or billing unit | Decision |
|---|---|---|---|
| Yahoo Search UI | Manual browsing and refinement. | Human effort; no bulk API rate in cited help. | Good for checking why a duplicate or surprising page appears. |
| SerpApi Yahoo Search API | Structured Yahoo organic results with an explicit result-offset parameter for separate page requests. | Its Starter plan lists $25/month for 1,000 successful searches; each successful page request counts as a monthly search. | Consider it when explicit offsets matter. Count usable unique URLs across those requests before comparing plans. |
| Serpent Yahoo Quick | Organic-only rows, with best-effort multi-result requests. | One Web-category call per Quick request. | Use when you only need URLs and a low-cost sample. |
| Serpent Yahoo Deep | Organic rows and rich blocks where present. | Web-category units by requested page. | Choose when richer context matters; measure unique yield per unit. |
Why might deeper results disappoint?
URL dedup is a policy, not a universal truth. HTTP and HTTPS, language paths, canonical tags and tracking parameters may point to the same content or different content. Normalize only what you can defend and retain original URLs. Do not infer that a short deep response has exhausted Yahoo results; inspect delivery and try a separate dated sample if the business decision is material.
Calculate the relevant yield at each depth
A deep request is worthwhile only if later rows add useful candidates for your specific task. Make a sampling ledger with requested depth, returned rows, valid-URL rows, distinct normalized URLs and manually useful URLs. Those are different denominators. In an illustrative three-page worksheet, 30 requested positions, 23 returned rows, 19 unique URLs and 7 relevant pages mean 7 review candidates, not a 30-result success. The numbers illustrate the calculation and are not an observed Yahoo response.
| Measure | Calculation | Why it matters |
|---|---|---|
| Unique yield | 19 unique URLs ÷ 3 requested pages = 6.33 unique URLs per requested page in the hypothetical sample. | Compare this with a smaller Quick sample using the same query and date. |
| Useful yield | 7 reviewed relevant URLs ÷ 3 requested pages = 2.33 useful URLs per requested page. | Choose depth by the information gained, not row count alone. |
| Duplicate burden | 23 returned rows − 19 unique URLs = 4 repeated normalized URLs. | Inspect whether normalization merged distinct language or product pages. |
Predeclare a stopping rule such as “stop requesting more depth when the last reviewed page adds no relevant unique URL in two dated samples.” A short result list can also reflect delivery limits, so it is not evidence that the search engine has no deeper results. If the decision only needs first-page brand presence, choose Quick; if it needs lesser-known domains, test whether Deep’s extra unique yield justifies its requested-page cost.
Decide when to stop
- Set a depth that answers the task and record the page count that will be billed before making a Deep request.
- Count requested positions, returned rows with valid URLs, and distinct normalized URLs separately. Keep the original URLs for review.
- Inspect duplicates, language paths and a few deep rows in the Yahoo interface; do not assume every short result means the index ended.
- Compute usable unique URLs per requested page for your sample, then decide whether Quick or Deep gives enough evidence.
Measure one deeper Yahoo sample
Start with the few queries that drive a real decision. Save the returned rows and their limits before increasing the schedule.
Get an API keyFAQ
Why can returned rows exceed unique URLs?
The same page can appear more than once or in URL variants. Keep raw rows and report unique normalized URLs separately.
Does num=30 guarantee 30 Yahoo results?
No. The documented requested depth is best-effort. Report returned rows and delivery information.
Which parameter wins if I send num and pages?
The public web contract says num takes precedence. Prefer one depth control in your client.
Should duplicates be discarded?
Remove duplicates from the unique-domain or URL count, but keep them in an audit record with both observed positions.






