Repository navigation
Feature request: a search-index enricher (domain -> indexed pages) backed by Serply #220
Description
Hi @dextmorgn,
I have been reading through flowsint-enrichers and the enricher-builder skill, and the one input pivot I cannot find anywhere in the catalog is a search index. There are 48 enrichers and none of them asks a search engine what is publicly indexed about a target. The closest are website_to_crawler and website_to_links, but both start from a URL you already have, so they widen a page rather than discover one.
I would like to add that pivot. Before writing anything I want to check whether you want it at all, and which direction you want first.
What the service is
Serply is a keyed API that returns Google results as JSON. One call:
GET https://api.serply.io/v1/search/?q=site%3Aflowsint.io&num=10
X-Api-Key: <key>
Accept: application/json
The response carries a results array of {position, title, link, description} rows, plus optional blocks for answers, related searches and news when Google returns them. I ran exactly that query today: HTTP 200, 9 organic rows, each with a title, a link and a description.
1 Flowsint - Automated graph analysis & intelligence https://www.flowsint.io/
2 Welcome to Flowsint - Documentation https://www.flowsint.io/docs/overview
3 Enrichers catalog - Documentation | flowsint.io https://www.flowsint.io/docs/sources/available-enrichers
Billing is per request on a self-serve key, so operationally it is the same shape as the keyed services already in the catalog (Dehashed, Scamalytics, Whoxy, Veriphone, HudsonRock, Etherscan) rather than a new kind of dependency.
What I would build
flowsint-enrichers/src/flowsint_enrichers/domain/to_indexed_pages.py:
| Piece | Value |
|---|---|
| class | DomainToIndexedPagesEnricher |
name() |
domain_to_indexed_pages |
category() / key() |
Domain / domain |
InputType / OutputType |
Domain / Website |
| params | one SERPLY_API_KEY vaultSecret, following ip/to_fraudscore.py |
scan() runs site:<domain> and pages through the result set; postprocess() emits one Website node per organic row and relates it back to the input Domain. The mapping needs no new type: link lands on Website.url (the primary field), title on title, description on description.
The value is that it surfaces pages DNS, certificate transparency and crawling all miss: hosts that only appear in Google's index, stale pages that still resolve but are linked from nowhere, exposed documents, and third-party pages that mention the target.
Which pivot do you want first
I sketched three, and I would rather build the one you want than the one I happened to pick:
domain -> Websitefromsite:<domain>, the one above. It slots straight into the existing domain flows.individual -> Websiteororganization -> Websitefrom a plain name query, for pages that mention a subject rather than pages the subject owns.organization -> Websiterestricted to news. Google'stbm=nwspasses through, so this is the same adapter with one extra parameter.
Two things I would get right in the first push
- Pagination.
startis the only parameter Serply honours.page,offsetandpare accepted and silently ignored, so a loop built on any of those refetches the first window forever and spends a credit per duplicate page. I verified this:start=10returns a window with no overlap against the base page, while the others return page one verbatim. numis an approximate cap of about 10 per page, not an exact count, so surplus rows need trimming on our side before they become nodes.
Disclosure, and the offer
I work on Serply, so weigh the recommendation accordingly. I am proposing it because the pivot is missing, not because the catalog needs another vendor.
If you want it, I will open a PR with the enricher, tests under flowsint-enrichers/tests/enrichers/, a row in docs/sources/available-enrichers.mdx, make lint / make typecheck / uv run pytest -q green, and a screenshot of the nodes it produces on a real sketch. Provider docs: https://serply.io/docs
If a search-engine source is out of scope for the catalog, or if you would rather it arrive as a configurable template enricher than as a Python module, say which and I will follow it.
Activity
dextmorgn commentedon Sep 18, 2026
hey @googio,
This is a very good idea and very valuable. I very much like the three enrichers you sketched.
You can draft a PR with a first enricher, tag me to make sure we're on the same path, and go on with the remaining two :)
Thank you so much !
googio commentedon Sep 18, 2026
Thanks @dextmorgn, that is the answer I hoped for.
#223 has the first one:
domain_to_indexed_pages, Domain to Website fromsite:<domain>. Tests, the docs catalog row, and a live run against a localNeo4j are in the body, plus the
make lint/make typecheck/pytestoutput.One thing I would rather you decide than guess at: I reused the
HAS_WEBSITEedge
domain_to_websitewrites, so indexed pages land in the same domain topage view. If you want discovered pages kept apart from the canonical site, say
so and I will switch it to a dedicated label.
Once you are happy with the shape I will follow with the other two.
googio commentedon Sep 19, 2026
@dextmorgn the other two are up, batching them into one note so this does not
spam you:
individual_to_mentions, Individual to Website. Runs the full name as anexact phrase and emits the public pages that mention the person.
org_to_news, Organization to Website. Same idea against the newsvertical, with a
time_rangefilter.All three are independent, so they can be merged, reordered or dropped one at a
time. Each carries its own tests, docs row and a live run against a local Neo4j.
Two things worth your call, both explained in the PR bodies:
HAS_WEBSITEfor pages found under adomain; feat(enrichers): add individual_to_mentions enricher backed by Serply #225 and feat(enrichers): add org_to_news enricher backed by Serply #227 introduce
MENTIONED_IN, because a name appearing ona page is evidence of a mention, not of ownership. I grepped the 34 labels
in use before adding one. If you would rather not grow the label set, tell
me what to use and I will change both.
Websitehas no date field, so I do not persist article publication datesanywhere. Adding a
published_attoflowsint-typesfelt like yourdecision rather than something to slip into an enricher PR. Happy to do it
as a follow-up if you want it.
No rush on any of them.