Link Extractor - All Links from Any Page with Anchor Text
Pricing
from $8.00 / 1,000 page scans
Link Extractor - All Links from Any Page with Anchor Text
Extract every link from any webpage. Input: a list of page URLs. Output: JSON with the absolute link URL, anchor text, internal/external type and rel flags (nofollow, sponsored, ugc), plus mailto and tel lists. $0.01 per page flat, however many links it finds. No start fee, no browser, no code.
Pricing
from $8.00 / 1,000 page scans
Rating
0.0
(0)
Developer
Broke to Built
Maintained by CommunityActor stats
0
Bookmarked
1
Total users
0
Monthly active users
10 days ago
Last modified
Categories
Share
Link Extractor - every link on a page, with anchor text and rel flags
Give it a page URL, get every <a href> on it - resolved to an absolute URL, classified
internal vs external, with clean anchor text and the rel attributes that matter for SEO
(nofollow, sponsored, ugc). mailto: and tel: links come back in their own lists.
One record per page, all links nested inside it, $0.01 per page scanned no matter how many links the page turns out to have. No API key, no browser, no crawl to configure.
What you get, per page
counts total, internal, external, nofollow, sponsored, ugc, mailto, tellinks[] href, text, type, rel, target, nofollow, sponsored, ugcmailto[] href, email, texttel[] href, tel, texturl, finalUrl, statusCode, redirected
- Absolute URLs. A page writes
/pricing; you gethttps://site.com/pricing. Resolution honours a<base href>element if the page has one, and otherwise resolves against the final URL after redirects - so a link list from a redirected page still points at the right host. - Clean anchor text. Nested tags stripped, HTML entities decoded (
&,’,—and ~60 named entities), whitespace collapsed. An anchor wrapping an icon and a span comes back as the words a human sees. - Internal vs external by hostname (see the honest limit on subdomains below).
- rel flags parsed, not just echoed.
rel="nofollow sponsored"becomesnofollow: true, sponsored: trueas well as the raw string. - Deduplicated on href + anchor text, so a nav link repeated in the footer appears once, while the same URL linked from two different phrases appears twice - which is what a link audit wants.
mailto:andtel:separated out with the address and number already parsed. Fragment-only (#top),javascript:,data:andabout:hrefs are dropped.
Input
{ "url": "https://apify.com/store" }
Bulk - one record and one charge per page:
{ "urls": ["https://apify.com/store", "https://en.wikipedia.org/wiki/Hyperlink"], "maxUrls": 50 }
| Field | Type | Default | Notes |
|---|---|---|---|
url | string | - | One page URL. A bare domain gets https:// prepended. |
urls | array of strings | - | Bulk list; takes precedence over url. |
maxUrls | integer | 50 | Hard cap on pages processed, and therefore on spend. |
Output - a real record
Verbatim from a live run on 2026-08-15, links truncated to the first three of 138:
{"url": "https://apify.com/store","finalUrl": "https://apify.com/store","statusCode": 200,"redirected": false,"counts": {"total": 138, "internal": 90, "external": 48,"nofollow": 19, "sponsored": 0, "ugc": 0, "mailto": 0, "tel": 0},"links": [{ "href": "https://apify.com/", "text": "", "type": "internal", "rel": null, "target": null, "nofollow": false, "sponsored": false, "ugc": false },{ "href": "https://console.apify.com/sign-up", "text": "Get started", "type": "external", "rel": null, "target": null, "nofollow": false, "sponsored": false, "ugc": false },{ "href": "https://console.apify.com/sign-in", "text": "Log in", "type": "external", "rel": null, "target": null, "nofollow": false, "sponsored": false, "ugc": false }],"mailto": [],"tel": []}
Two things in that record are worth pointing at, because they will surprise you otherwise:
console.apify.comis typed external. Classification compares the exact hostname, so a subdomain of the same site counts as external. If you are auditing a site that spanswww.,blog.andapp.subdomains, group by hostname yourself rather than trustingtype.- The first link has
"text": "". That is a logo anchor wrapping an image - a real, correctly reported empty anchor, and exactly the kind of thing an accessibility or SEO audit is looking for.
The same run on https://en.wikipedia.org/wiki/Hyperlink returned 436 links (288 internal,
148 external, 44 nofollow) in one record, for the same $0.01.
Call it from code or an agent
curl -X POST "https://api.apify.com/v2/acts/EliAI~webpage-links-extractor/run-sync-get-dataset-items?token=$APIFY_TOKEN" \-H "content-type: application/json" \-d '{"urls":["https://example.com"],"maxUrls":50}'
Agents can call it as a tool over Apify MCP:
- Capability: list every hyperlink on one or many pages, with anchor text and rel flags
- Required input:
url(string) orurls(array) - Returns: one JSON record per page;
countsfor a summary,linksfor the detail - Bounded:
maxUrlscaps the run; it does not follow links or crawl - Side effects: none - one GET per page
Pricing
$0.01 per page scanned - one page-scanned event per URL that returned a usable HTML
response. No actor-start fee, and the price does not move with the number of links: the
138-link page and the 436-link page above each cost $0.01.
Honest comparison, measured on the store 2026-08-15. The shape of the price is the whole difference here:
| Actor | Price shape | A 436-link page |
|---|---|---|
| eliai/webpage-links-extractor (this one) | $0.01 per page, no start fee | $0.01 |
automation-lab/link-extractor | $0.035 start + per-URL event | $0.035 before a single link |
ninhothedev/website-link-extractor | $0.00005 start + $0.0005 per dataset item | $0.22 if each link is an item |
codescraper/website-social-links-scraper | $0.00005 start + $0.0005 per item (+$0.002 per social profile) | scales the same way |
Per-dataset-item pricing gets cheaper than this on pages with very few links, and more expensive as pages get link-heavy - a real site's navigation alone is often 80+ links. A flat per-page price is predictable, which is the property that matters when a script or an agent is deciding how many pages to scan.
When NOT to use this
- Crawling a site. It does not follow links. Give it the URLs you want; to discover them, use Sitemap URL Extractor.
- Checking whether the links work. It reports what the page links to, not what those URLs answer. For that use Broken Link Checker or Redirect Chain Checker.
- Links injected by JavaScript. The served HTML is parsed with no browser, so anchors that a client-side framework renders after load are not there to find.
- Treating subdomains as one site.
typecompares exact hostnames - see the note above. - Harvesting email addresses at scale.
mailto:links are returned because a contact page's address is a legitimate part of a link audit; scraping addresses for unsolicited mail is not what this is for, and it is your obligation under GDPR/CAN-SPAM either way. - Pages behind a login or aggressive bot protection. It fetches anonymously - no cookies, no session, no proxy rotation.
FAQ
How do I get all the links on a webpage with their anchor text?
Pass the URL. Every <a href> comes back as an absolute URL with clean anchor text, deduplicated,
with mailto: and tel: in their own lists - one JSON record for the whole page.
Can it tell internal links from external ones?
Yes, by hostname, with counts.internal and counts.external for the summary. Note that a
subdomain (blog.site.com seen from site.com) is typed external - group by hostname yourself if
you want registrable-domain semantics.
Does it show nofollow, sponsored and UGC links?
Yes - the raw rel string plus parsed booleans per link, and totals in counts. That is what a
link-equity or paid-placement audit needs.
Why do absolute URLs matter?
A relative href like /pricing is meaningless once the link leaves the page. Resolution respects
<base href> and the post-redirect URL, so every href in the output works standalone in a
spreadsheet, a crawler queue, or a model's context.
Can I extract links from many pages at once?
Yes - pass an array in urls, capped by maxUrls (default 50). One record and one $0.01 charge
per page, and one bad URL never stops the others.
How are duplicate links handled? Deduplicated on href plus anchor text. The same nav link repeated in the footer collapses to one entry; the same target linked from two different phrases stays as two, because those are two different signals in an SEO audit.
Does it follow the links it finds? No. It reads one page per URL you pass and does not crawl. That is what keeps the price flat and the run bounded.
What happens on a page that is not HTML, or that fails to load?
You get a record with an error field instead of links, the run continues, and that URL is not
charged.
Related actors
- Broken Link Checker - crawl a page and find every dead link
- Redirect Chain Checker - trace every 301/302 hop to the final URL
- Outbound Link Auditor - audit who you link out to
- Sitemap URL Extractor - every URL a site declares
- Webpage Text Extractor - the readable content of the same page
- Contact Details Extractor - emails, phones and socials from a site
Built by Broke to Built.
For AI agents
This Actor is built to be called by software, not just by people.
- Mount it directly as an MCP tool — no Store search, no ranking, just this one tool:
https://mcp.apify.com/?actors=eliai/webpage-links-extractor - Or call it over HTTP and get the results in the same request:
POST https://api.apify.com/v2/acts/eliai~webpage-links-extractor/run-sync-get-dataset-items - Pay with x402, without an Apify account. This Actor is whitelisted for agentic payments, so an agent holding USDC on Base can buy a prepaid token and spend it here. The minimum purchase is $1, the token balance is an absolute spending cap, and it expires 14 days after purchase.
- Costs are predictable before you call. Pricing is pay-per-event (see Pricing above), so an agent can budget a run in advance instead of discovering the bill afterwards.
- Send only the field you mean. If you pass the bulk field, it is used on its own; the single-value field is a fallback, never merged into your request. You are charged for the items you sent and nothing else.