AI Watch

Labelling 50,000 Web Resources with LLMs for Free: What Worked When the Official APIs Said No

By Lesia Kapliuk · November 3, 2026

Labelling 50,000 Web Resources with LLMs for Free: What Worked When the Official APIs Said No

TL;DR: We had to sort tens of thousands of web resources (about 50,000) into categories and tags. Each needs about a dozen fields, read from its description and rules, and some of the content is adult.

  • Our Claude Pro and Google AI Pro subscriptions handled the first 5,000 items, but they don't scale to the rest.
  • Google's free API blocked every adult item once our prompt got more detailed. The same model on another host labelled every one.
  • The job now runs for $0 on NVIDIA's Nemotron 3.5 Super VL, called through two free tiers: NVIDIA's own API and OpenRouter. Against a reference made by Claude Opus it scored on par with Claude Sonnet: 73–77% of fields matched for Nemotron, 70% for Sonnet, on a small sample.
  • It labels 250–450 items an hour, depending on load and how many calls run in parallel.

The task

We keep a catalogue of web resources. Each entry has a short description and a set of rules: what may be published there, which links are banned, whether promotion is allowed. For every entry we want structured labels:

  • a few single-choice fields: who appears in the content, who it is for, how it is produced, the main category;
  • niche tags from a vocabulary of roughly 200 values, plus up to three free-text tags for anything the vocabulary misses;
  • facts from the rules: whether commercial content is allowed, where promotion is allowed, what a title must contain, and similar.

The model returns one JSON object per entry. The prompt, with the full vocabulary and the JSON schema, is long: a call with one entry comes to about 3,800 input tokens. There are about 50,000 entries, and about 260 new ones become ready for labelling every hour.

Part of the catalogue is adult content. That one fact shaped everything below.

Round 1: the subscriptions we already pay for

Claude Code (Claude Pro). Claude Code runs headless (claude -p), so a script can feed it batches. We sent 20 entries per call to Sonnet at low effort, with our own system prompt and no tools.

  • One batch took 26–29 seconds and used about 50k input and 4.6k output tokens. That is more than our prompt and 20 entries add up to. We assume the difference is context Claude Code adds to every call, even headless.
  • 100 entries used about 9% of the plan's 5-hour window and about 1% of the weekly limit.
  • A scheduled task ran every 30 minutes and checked plan usage first. It stopped at 90% of the 5-hour window or 95% of the week.
  • In two days it labelled the 5,000 most important entries, with no refusals that we noticed.

That's good quality at no extra cost, but it doesn't scale. At that rate, 50,000 entries would eat a big share of the weekly limit for weeks, and we use the plan for other work too.

Google Antigravity (Google AI Pro). We tried Gemini 3.8 Flash by hand in Antigravity on a 20-entry sample, in batches, at low and high reasoning. At that point we scored against Sonnet's labels, because the Opus reference described below didn't exist yet.

  • Low reasoning answered a batch in 13–15 seconds. When it answered, it agreed with Sonnet on 13 of 14 entries for most fields.
  • The catch is refusals. Some batches were refused whole, and the app doesn't say which entry triggered it. One batch went through only after we removed one niche entry from it. At high reasoning, one batch was refused after 242 seconds of work.
  • High reasoning also started searching the web on its own (5–6 searches per batch, up to 96k input tokens, up to 7 minutes) and used about 2% of the 5-hour quota per batch.

Low reasoning labelled 14 of 20 entries and high reasoning 9 of 20. A pipeline can't rely on that.

Round 2: Google's free API, and the filter you can't turn off

Google AI Studio has a free tier for the open Gemma 4 models, and Gemma looked like the obvious workhorse.

  • The first tests went fine. With our first prompt, Gemma 4 26B labelled all 20 test entries and agreed with Sonnet on most fields.
  • It was slow. Gemma 4 always "thinks" first, and the API ignores the settings that are supposed to limit that. Calls took 40–170 seconds. For the background worker we switched to Gemma 4 31B.
  • Then we improved the prompt and everything stopped. We added sections on commercial content and title requirements, both everyday moderation topics. After that, Google blocked 20 of 20 entries for Gemma 4 31B with PROHIBITED_CONTENT, including entries that had passed the day before. The 26B model was blocked the same way. We ran the entries one at a time with nothing else running, so it wasn't a rate limit.

What we learned:

  • The filter judges the whole prompt, not only the entry. Instructions plus a borderline entry can tip it, and which sentence tips it differs from entry to entry. Editing the prompt to fix this is guesswork.
  • The block comes back as PROHIBITED_CONTENT, which is not one of the adjustable safety filters, so there is no setting to turn it off.
  • The model is not the problem. The same Gemma 4 31B, called through a third-party host (DeepInfra via OpenRouter), labelled 30 of 30 entries with the same prompt in about 7 seconds each. OpenRouter also lists a free Gemma 4 31B, but only Google AI Studio serves it, so the same filter applies. That's why we paid DeepInfra for this test.

How many items each route actually labelled

Round 3: a reference, then the free tiers

To compare models fairly, we first made reference labels. Claude Opus at medium effort labelled a 30-entry sample once, in a Claude Code subagent. We used Opus rather than Sonnet because Sonnet was one of the candidates being scored. For every other model we counted how many fields matched Opus exactly.

Then we looked for free or nearly free sources that met three requirements:

  • an OpenAI-style chat API;
  • no blanket adult-content filter;
  • a rate limit that allows thousands of calls a day.
Model (host)LabelledMedian seconds per itemFields equal to OpusCost
Nemotron 3.5 Super VL (OpenRouter :free)25/30 (5 cut by output limit)3377%free
Nemotron 3.5 Super VL (NVIDIA API)30/303073%free
DeepSeek V4.1 Flash (OpenRouter)28/301472%~$0.002 per item
Claude Sonnet, low effort (Claude Code)11 of the 30, earlier runn/a70%subscription quota
Nemotron 3 Ultra (OpenRouter :free)30/307168%free
Gemma 4 31B (OpenRouter, DeepInfra)30/30757%~$0.001 per item

How often each model agreed with the reference labels

How to read this table:

  • The sample is small. Sonnet's figure covers only the 11 entries it had labelled earlier. The same Nemotron scored 77% through one host and 73% through the other, and that gap is as large as the gap to Sonnet. The fair conclusion is that the free Nemotron is about as good as Sonnet for this task, not better.
  • Niche tags agree worst for every model. Opus is no more certain there either, because many entries plausibly fit several niches.
  • Nemotron writes long reasoning before the JSON: about 5,000 output tokens per entry. With an 8,192-token output limit, 5 answers were cut off. At 16,384 tokens none were.
  • DeepSeek is the deepseek/deepseek-v4.1-flash variant on OpenRouter ($0.045 per million input tokens, $0.50 per million output). A dated variant costs about three times as much for input.

Some candidates didn't make the table:

  • DeepSeek and GLM on NVIDIA's free API sat in a queue for about four minutes or returned 504.
  • Kimi K2.6 on NVIDIA returned 404.
  • Gemini 3.5 Flash Lite through AI Studio got the same prompt that had Gemma blocked. It passed 10 of 11, though on a different set of entries, so we can't tell whether the model or the entries made the difference. Scored against Sonnet, like Antigravity, it agreed on only 37 of 64 fields.

The fine print on "free"

  • NVIDIA API (build.nvidia.com): free with an account key. The catalog page doesn't state a rate limit. At 4 parallel calls we never hit one, and at 8 we saw occasional 429s. Latency depends on load: a median of 25–30 seconds in the evening and 60–80 seconds at night (European time).
  • OpenRouter :free models: 20 requests a minute, and 50 requests a day, or 1,000 a day once you've bought at least $10 in credits. We checked the case where you go past the daily quota: OpenRouter answers HTTP 429 and charges nothing, and the free model never falls back to the paid one. The daily counter resets at 00:00 UTC.
  • We told OpenRouter to skip Google-hosted providers, so the same filter couldn't come back through the router.
  • Requesty, another router with the same OpenAI-style API, gives new organizations 200 free requests a day and 20 a minute, and paying ones 1,000 a day and 60 a minute. Its free models are mostly the ones OpenRouter offers. Nemotron 3.5 Super isn't among them, and the free Nemotron it does list returned 404 when we tried it. Our worker can call Requesty, so it can become a third source if it ever offers a model worth using.

What it costs if you pay

On cost, one mistake is easy to make (we made it in our own notes). The price per item is tiny. The total depends on how many items you count, and our queue kept growing while we planned this.

What labelling 10,000 items costs through the API

The DeepSeek and Gemma figures are what OpenRouter actually billed on the test sample. DeepSeek reasons at length: OpenRouter reported about 2,800 output tokens per entry, while Gemma answers in about 300. For DeepSeek the bill came out about 30% above what those tokens cost at the list price. OpenRouter routed our calls to about ten different providers, and some of them probably charge more than the cheapest one.

When our queue held 1,500 entries, DeepSeek looked like a $3 job. The whole remaining catalogue, about 40,000 entries still to come, would cost about $85 with DeepSeek or $40 with Gemma. Qwen 3.7 Flash would be roughly $20, but that's an estimate from its list price: we haven't tested its quality or measured its output length.

None of that is expensive. It's still more than $0 for labels that agree with the reference no better than the free Nemotron's.

How it runs now

The worker sends one entry per call and switches between the two free sources in turn. That way a refusal or a cut-off costs one entry, not a batch of 20. Several calls run in parallel, each in its own lane. A 429 pauses that source for all lanes, until the time the provider gives, or for an hour after a daily quota.

The first night (14 hours, 20:00 to 10:00 UTC, 4 lanes):

  • 3,451 entries labelled, about 250 an hour on average: around 350 an hour in the evening, 110–265 later in the night as NVIDIA slowed down.
  • 1,909 went through NVIDIA and 1,542 through OpenRouter. The OpenRouter number is above the 1,000-a-day quota because the night crossed the 00:00 UTC reset: 633 entries came before it and 909 after. That second quota ran out around 08:00 UTC, after which NVIDIA carried on alone at about 180–240 an hour.
  • A few dozen calls failed (network timeouts, 500s, answers cut off). Those entries are retried later automatically.

More parallel calls help. With NVIDIA alone, we raised the number of lanes from 4 to 8:

  • In the first 20 minutes NVIDIA's median latency jumped from about 40 to 107–150 seconds, and only 54 entries came through.
  • Over the next two hours it settled at 300 and then 450 an hour.

That's faster than new entries arrive, so the backlog (about 4,000 at the time of writing) is shrinking.

Labels follow the prompt. Every label stores the model and a hash of the prompt that made it. Once nothing new is waiting, the worker relabels entries made with an older prompt, largest first. So a prompt change reaches the whole catalogue on its own over a few days. That includes the 5,000 entries Sonnet labelled, so nothing depends on a subscription any more.

Takeaways

  1. For adult or borderline data, the host can matter more than the model. Google's API blocked Gemma 4 31B on every item. DeepInfra ran the same model without complaint.
  2. Subscriptions are great for a first pass and for reference labels, not for bulk work. Claude Code labelled 5,000 entries within plan limits. The consumer apps refuse whole batches without saying why, and the quota is shared with everything else you do.
  3. Make a reference with the strongest model you can afford once, and score everything against it, including the model you were going to use anyway. On our sample a free open model matched Sonnet.
  4. Free tiers are real, but read the limits. NVIDIA's API and OpenRouter's :free models together give us thousands of labels a day for $0, plus a one-time $10 top-up.
  5. Send one item per call. Batching saves quota on subscriptions, but on an API it just multiplies the damage of each refusal.

FAQ

Is Nemotron really as good as Claude for this? On our 30-entry sample, scored against Opus, Nemotron 3.5 Super VL matched 73–77% of fields and Sonnet 70%, the latter on only 11 entries. That's one task and one prompt: read it as "on par", not as a general ranking.

Can I turn off Gemini's PROHIBITED_CONTENT block? No. It is not one of the adjustable safety filters, so there is no setting for it.

Will OpenRouter charge me if I go over the free quota? Not for a :free model. It returns 429 until the daily reset.

How long will 50,000 entries take? New entries arrive at about 260 an hour, and the source that produces them needs about six more days. The labels catch up with the backlog within a day or two at 8 lanes, then keep pace with new arrivals, so the whole catalogue should be labelled within about a week.

Sources