metafetch

Metafetch fills fields from any data API: funding rounds from Fireround, brand colours and blocked pages from Firecrawl

A Tooling note can now carry the company's latest round and lead investors. Sites that refuse a plain fetch come through Firecrawl. Any other JSON API is a recipe file.

Why Care?

Some of what you want on a note about a company isn't on its homepage at all: when it last raised, how much, who led. And some homepages won't talk to a plain fetch. They answer with a 403 or a bot check, and the fields stay empty.

Metafetch can now ask a data API for those fields. Which API is up to you, and adding a new one doesn't need a new version of the plugin.

What's New?

  • Funding rounds on a Tooling note. from: [fireround] fills the latest round, amount, date, lead and other investors, total raised, earlier rounds, and the articles it was verified against, from Fireround's feed. It's matched on the note's domain, so a company with a similar name is never written.

  • A fallback for sites that refuse a plain fetch. from: [direct, firecrawl] reads the page directly first and asks Firecrawl only if that fails.

  • Brand colours and fonts. from: [firecrawl-branding] reads a site's primary, secondary, and accent colours, colour scheme, and fonts.

  • One key for all three. Settings has a single Firecrawl group, and that key only ever goes to api.firecrawl.dev.

  • Any other data API as a recipe file, with kind: data. A recipe file with provider: firecrawl borrows the Firecrawl key, so anything in Firecrawl's provider catalogue is one file away.

How it works

A profile field names a recipe and one of its outputs:

YAML
latest_round:   { from: [fireround], value: round }
lead_investors: { from: [fireround], value: lead_investors }
og_image:       { page: image, from: [direct, firecrawl] }

The recipe owns its output names and the profile owns your vault's key names, so either can change without breaking the other. Sources run cheapest first: the free parse, then data recipes, then a model, which fills only what's left. Each recipe is called at most once per note, and only if a field still needs it.

Proof

Live, through the plugin's engine:

  • Fireround on firecrawl.dev, 0.9 s: Series B, $75M, 2026-09-22, led by Smash Capital, Series A before it, three sources.

  • Firecrawl on tina.io, 0.4 s: title, description, share image, favicon, site name.

  • Firecrawl Branding on tina.io, 4.6 s: #EC4815 / #1C1B2E / #0D5DBD, light, IBM Plex Sans and Inter.

How a borrowed key stays safe

  • A recipe's key goes only to the hosts of the recipe that holds it. A file with provider: firecrawl that points at any other host is refused before anything is sent.

  • Only data recipes can borrow a key, and only from a recipe that holds its own. A chain of borrowing can't widen where a key goes.

  • A recipe file with its own key sends nothing until you approve its host in settings, as before.

  • Only text, numbers, yes/no, and lists of those are written. Objects and inline data: images are dropped.

Under the hood

  • modelRecipes.ts: kind and provider on every recipe; BUNDLED_DATA_RECIPES and ALL_BUNDLED_RECIPES; callData() beside callModel(), both on a shared send() that places the key and checks the host; keyHolderFor(), acceptDataValue(), domainOf(); readPath() learns [*]. Data recipe files declare response.outputs (one path or a list to try in order), and optionally records, match, and error. Body variables are {{url}}, {{domain}}, and {{title}}, URL-encoded when they're used in the URL.

  • frontmatterProfiles.ts: from: entries other than direct and model are recipe ids; value: names the output and defaults to page:; FillReport.forRecipes.

  • modelProviderSettings.ts: one group per key holder, listing the recipes that borrow it; the default-model dropdown lists model recipes only.

  • The example Tooling profile ships the funding and brand fields commented out, so a vault without a Firecrawl key never sees errors.

  • 17 new tests (175 total).

What's Next

  • Moving Microlink onto a recipe, to prove the format against a provider that already works (the exploration's question 6).

  • Feeding Firecrawl's page text to the model step when a plain fetch is refused. Today the model still needs the direct fetch to succeed.