Skip to content

Feature request: a search-index enricher (domain -> indexed pages) backed by Serply #220

Description

@googio

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:

  1. domain -> Website from site:<domain>, the one above. It slots straight into the existing domain flows.
  2. individual -> Website or organization -> Website from a plain name query, for pages that mention a subject rather than pages the subject owns.
  3. organization -> Website restricted to news. Google's tbm=nws passes through, so this is the same adapter with one extra parameter.

Two things I would get right in the first push

  • Pagination. start is the only parameter Serply honours. page, offset and p are 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=10 returns a window with no overlap against the base page, while the others return page one verbatim.
  • num is 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

  1. dextmorgn commented on Sep 18, 2026

    @dextmorgn
    Collaborator

    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 !

  2. googio commented on Sep 18, 2026

    @googio
    Author

    Thanks @dextmorgn, that is the answer I hoped for.

    #223 has the first one: domain_to_indexed_pages, Domain to Website from
    site:<domain>. Tests, the docs catalog row, and a live run against a local
    Neo4j are in the body, plus the make lint / make typecheck / pytest output.

    One thing I would rather you decide than guess at: I reused the HAS_WEBSITE
    edge domain_to_website writes, so indexed pages land in the same domain to
    page 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.

  3. googio commented on Sep 19, 2026

    @googio
    Author

    @dextmorgn the other two are up, batching them into one note so this does not
    spam you:

    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:

    1. The relationship label. feat(enrichers): add domain_to_indexed_pages enricher backed by Serply #223 uses HAS_WEBSITE for pages found under a
      domain; 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 on
      a 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.
    2. Website has no date field, so I do not persist article publication dates
      anywhere. Adding a published_at to flowsint-types felt like your
      decision 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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions