Elixir
Scrape your first page from Elixir using Req — the de facto modern HTTP client, single-dependency, ergonomic.
Submit a scrape, poll for the result, and handle transient errors — using Req, the modern Elixir HTTP client (already bundled with Phoenix 1.7+).
Authentication
Set your API key as an environment variable. Get a key from the Dashboard.
export ANAKIN_API_KEY=ak-your-key-hereThe base URL is https://api.anakin.io/v1. Every request authenticates via the x-api-key header.
Install
Req is the de facto modern HTTP client in Elixir — JSON encode/decode, retry, and connection pooling all built in. Phoenix 1.7+ already bundles it; standalone projects need one dep:
Add to mix.exs:
defp deps do
[
{:req, "~> 0.5"}
]
endThen:
mix deps.getScrape a page
Save as lib/quickstart.ex:
defmodule Quickstart do
@base "https://api.anakin.io/v1"
defp api_key do
System.get_env("ANAKIN_API_KEY") || raise "ANAKIN_API_KEY is not set"
end
defp request(method, path, body \\ nil) do
Req.request(
method: method,
url: @base <> path,
headers: [{"x-api-key", api_key()}, {"content-type", "application/json"}],
json: body,
receive_timeout: 30_000
)
end
def scrape(url) do
{:ok, %{body: submitted}} = request(:post, "/url-scraper", %{url: url})
job_id = submitted["jobId"]
Enum.reduce_while(1..60, nil, fn _, _ ->
case request(:get, "/url-scraper/#{job_id}") do
{:ok, %{body: %{"status" => "completed"} = job}} ->
{:halt, job}
{:ok, %{body: %{"status" => "failed", "error" => err}}} ->
raise "scrape failed: #{err}"
_ ->
Process.sleep(3_000) # retry transient errors
{:cont, nil}
end
end)
|> case do
nil -> raise "timed out after 3 minutes"
job -> job
end
end
end
job = Quickstart.scrape("https://example.com")
IO.puts(job["markdown"])Run it:
mix run lib/quickstart.exWhat this does
- Submits
https://example.comto/url-scraperand gets back ajobId. - Polls
/url-scraper/{jobId}every 3 seconds (up to 60 attempts = 3 minutes). - Retries transient network errors silently — only surfaces real failures.
- Prints the final
markdownwhen the job completes.
Most jobs finish in 3–15 seconds.
Go further
Extract structured JSON with AI
Replace the submit body with generateJson: true to have AI return structured data:
{:ok, %{body: submitted}} = request(:post, "/url-scraper", %{
url: "https://news.ycombinator.com",
generateJson: true
})The completed response includes a generatedJson field with structured data inferred from the page.
Scrape JavaScript-heavy sites
For SPAs and dynamically-loaded pages, add useBrowser: true:
{:ok, %{body: submitted}} = request(:post, "/url-scraper", %{
url: "https://example.com/spa",
useBrowser: true
})Only use browser mode when needed — standard scraping is faster and cheaper.
Use it from Phoenix
Wrap scrape/1 in a GenServer or schedule via Oban — the polling loop blocks for up to 3 minutes per URL. For Phoenix LiveView, kick off scraping in a Task.async/1 and update the LiveView when the result arrives.