The Stalled-Dependency Verdict: Adopt, Fork, Replace, or Contain
Score one stalled dependency on five dimensions from public evidence and reach the same Adopt, Fork, Replace, or Contain verdict and review date a colleague would.
Key takeaways
- A quiet dependency with no unanswered bugs or security reports is finished, not dead, and the right verdict for it is Contain, not a fork or a migration.
- OpenSSF Scorecard's Maintained check only looks at the last 90 days and its own documentation admits small finished utilities can score as unmaintained, so a low score is a reason to look, not a verdict.
- Fewer than 5% of abandoned npm packages clearly announce end of life, so silence is the normal signal and waiting for a notice wastes the week.
- Only PyPI offers a third-party route to take over an abandoned name, and PEP 541 needs three contact attempts over six weeks, so on npm and crates.io taking over maintenance usually means forking under a new name.
- In Avelino et al.'s study, 41% of 315 abandoned projects survived because new core developers arrived, but 86% of those rescues depended on a single person, so one rescuer is not a credible successor.
- A dormant package keeps a live publish path: PyPI has unverified over 1,800 email addresses on expired or expiring domains, so takeover risk gets scored separately and sets a pinning floor under every verdict.
A dependency you already ship has stopped getting releases, and nobody answers its issues. This guide is the scoring standard for deciding, within a week, whether to adopt it, fork it, replace it, or contain it. It is for engineering managers, technical founders, and the engineers they hand the job to. You get five dimensions scored from public repo and registry evidence, a fixed rule that turns those scores into one verdict, and a dated review trigger that a second engineer scoring the same package should match.
The four verdicts and what each one commits you to
A gone-quiet dependency gets one of four verdicts: Adopt (take over the original package and its publish rights), Fork (maintain your own copy under a new name), Replace (migrate to a different library), or Contain (freeze the package behind a wall and review it on a set date). Each one commits you to a different kind of work, so the choice is a staffing decision as much as a technical one.
| Verdict | What you do | What it costs | Default review trigger |
|---|---|---|---|
| Adopt | Get publish rights on the original name | Maintenance for every user | 90 days after takeover |
| Fork | Patch and publish under a new name | Maintenance plus a rename | 90 days after first fork release |
| Replace | Migrate to a maintained successor | One-time migration | The migration due date |
| Contain | Pin, wrap, and monitor | Low now, risk builds up | 90 days, or any new advisory |
Two points to settle before you score anything.
- Adopt is rarer than people expect. Outside PyPI, no registry route lets a third party take over a name without the current owner's agreement. On most registries, "take over maintenance of an abandoned package" turns into a fork under a new name. The registry section below has the rules.
- Contain counts as a decision. It is the right answer for a finished library with nothing unanswered. It is also the holding pattern while a Replace migration lands.
Finished or dead: how to tell if an open source library is abandoned
A library is abandoned when bug or security reports go unanswered and nobody with publish rights acts on them. A library that is quiet but has nothing unanswered is finished, and a finished library needs no rescue.
What the Scorecard Maintained check proves
Most teams start with the Maintained check in OpenSSF Scorecard, a project that runs 18 security-related checks against public repositories. The Maintained check works like this:
- An archived project gets the lowest score.
- A project with at least one commit per week across the previous 90 days gets the highest score.
- Issue activity from collaborators, members, or owners earns a partial score. The check documentation does not give the exact formula for partial scores.
- The check only succeeds on projects more than 90 days old.
What it proves: whether people with commit rights were active in the last 90 days. When it lies: Scorecard's own documentation says some software, especially small utility functions, does not normally need maintenance. Its example is a library that determines whether an integer is even. The check also describes itself as retrospective, a short-term snapshot of the past 90 days. Treat a low Maintained score as a reason to look, not as a verdict. Scorecard tells you to decide for yourself whether the software is the kind that would not normally need active maintenance.
Registry status markers are sparse
PyPI supports three standard project statuses: active (the default), archived, and quarantined. Archiving disables new release and distribution uploads. Tooling has started to read these markers: uv audit reports adverse project statuses, and Composer has configuration keys for abandoned packages that now fall back to its policy settings. The trouble is that a marker only appears if the maintainer sets it, and people who walk away rarely do. One importer checked about 145 known obsolete or abandoned PyPI projects and found only six marked archived (PIL, argparse, enum, google-cloud, pathlib, typing).
How often packages go quiet
Two large studies measured abandonment. Their findings frame what you should expect.
| Study | Sample | Abandoned | Survived or announced |
|---|---|---|---|
| Avelino et al. (GitHub) | 1,932 projects | 315 (16%) | 128 (41%) survived |
| Miller et al. (npm, CMU) | 28,100 packages | 4,108 (14.6%) | Under 5% announce EOL |
Both studies put abandonment at roughly 15% of established projects. If your lockfile is long, you probably have more than one package in this state already.
The five dimensions and their scoring anchors
Score each dimension 0, 1, or 2 against fixed anchors, and attach one dated public artifact to every score. On four dimensions a higher number means more pressure to act. The exception is Successor availability, where 2 means a credible successor exists.
| Dimension | 0 | 1 | 2 |
|---|---|---|---|
| Abandonment confidence (A) | Release or merged fix in last 90 days | Quiet, nothing unanswered | Archived, or bug/CVE unanswered with no owner reply |
| Exposure (E) | No advisory, no open bug you hit | Advisory or bug, unused path proven | Advisory on shipped version, path not ruled out |
| Integration depth (D) | Behind one wrapper you own | Direct calls, internal code only | In your public API, stored data, or pulled in transitively |
| Successor availability (S) | Nothing found | Fork or handoff resting on one person | Maintained successor with releases and 2+ publishers |
| Takeover risk (T) | An owner active and reachable | Dormant owners, registry caps credentials | Expired domain, or credential controls unconfirmed |
Abandonment confidence (A)
What it proves: that nobody with publish rights will fix a problem you report. Evidence: last release date, last commit date, Scorecard Maintained result, registry status, the GitHub archived flag, links to unanswered bug or CVE issues, and the owner's response (or silence) to your contact message.
PyPI's PEP 541 abandonment test makes a useful cross-check. It requires all three of: the owner cannot be reached, there has been no release in twelve months, and the owner shows no activity on the project's home page. When it lies: bots or triage volunteers touching issues can produce a partial Maintained score even though no fix has shipped. Score on releases and merged fixes, not issue activity.
Exposure (E)
What it proves: that the stall can hurt you now, not only in theory. Evidence: open advisories against the exact version in your lockfile, and open bug reports you can reproduce. A 1 needs a written argument that the vulnerable function is never called from your code. No standard reachability method exists, so write down how you checked. When it lies: in a project nobody watches, "no advisory" mostly means nobody filed one. Treat a clean advisory feed on a dead package as weak evidence.
Integration depth (D)
What it proves: how much a Replace or Fork will cost. I could not find an established public method that combines call-site counts, transitive dependents, and reachability of the vulnerable path into one depth measure. The nearest academic work is Miller et al.'s Abandabot, a research prototype for spotting abandonment that actually matters to a downstream project. So the anchors here are structural and checkable. Ask where the package's calls and types show up, and whether another dependency you ship pulls it in. A transitive pull scores 2, because you cannot remove the package by editing only your own code. When it lies: a low call count can hide a type that leaks into your public API or your persisted data. Search for the types as well as the calls.
Successor availability (S)
What it proves: that a maintained path exists that you did not have to build. Evidence: forks with published releases, new committers on the original repo, a handoff note in the README or issues, a deprecation notice naming a replacement, and the registry owners list on the candidate. When it lies: a fork with stars and no releases, or a rescue that rests on one person. In Avelino et al.'s study, 86% of rescued projects drew exactly one new core developer, so a single rescuer scores 1, not 2. Those rescues also happened inside the original repositories, not through forks, so check the original repo's recent committers before you go hunting for forks.
Takeover risk (T)
What it proves: that someone other than the maintainer could publish a release you would pull in. A dormant package still has a working publish path, and that path is the attack surface.
The publish path of a dormant package
- Registry statusActive, archived, or quarantined; PyPI archiving blocks uploads while it holds
- Owner accountsHow many owners, and whether any acted or replied in the last 90 days
- Email domainsAn expired maintainer domain can be re-registered and used to recover the account
- CredentialsLong-lived tokens versus capped tokens and short login sessions
- Publish methodToken upload from a laptop versus OIDC trusted publishing from CI
The evidence behind each layer:
- Email domains. PyPI now checks whether the domains of verified email addresses have expired or are entering expiration, and marks those addresses unverified. It has unverified over 1,800 addresses this way. Domain-resurrection takeover has happened to at least one PyPI project, in 2022. Check the WHOIS expiry of every maintainer domain you can see in package metadata and commit history.
- Credentials on npm. npm has permanently revoked classic tokens, capped write-capable granular tokens at a 90-day maximum lifetime, and moved interactive login to short sessions. The session length has already changed once, so check the current value before you rely on it. Equivalent controls on crates.io and RubyGems are not established in the sources I used, which is why a dormant owner on those registries scores 2 unless you can confirm otherwise.
- Publish method. npm OIDC trusted publishing supports GitHub Actions and GitLab CI/CD. It is not established publicly what happens to a trusted-publishing binding when the bound repository changes owner. If the repo or its organisation has changed hands, flag it.
- Archiving. PyPI archiving disables uploads while the status holds. I could not establish whether a hijacked account could reverse it, so archiving does not lower T below what the email-domain check found.
A dormant package still has a live publish path, and nobody is watching it.
Turning five scores into one verdict
Apply six ordered rules and stop at the first that matches, then apply the takeover overlay. Running the rules in order, rather than weighting a total, is what makes two engineers land on the same verdict.
- A = 0 → Not stalled. No verdict. Re-score in 90 days.
- A = 1 and E = 0 → Contain. The library is finished.
- S = 2 → Replace. If D = 2, contain until the migration lands.
- D = 2, and you have publish rights on the original name in writing by the decision date → Adopt.
- E = 2 or D = 2 → Fork.
- Anything else → Contain.
Takeover overlay: if T = 2, pin the package to its exact version and integrity hash today, under any verdict, and treat any new release of it as something to inspect before admitting it. T never picks the verdict. It sets the minimum level of containment underneath it.
Worked through: a crate on crates.io scores A = 2, E = 1, D = 2, S = 0, T = 2. Rules 1 to 3 do not match. Rule 4 fails because crates.io will not transfer the name without the owner's approval and the owner has not replied. Rule 5 matches on D = 2, so the verdict is Fork, and the overlay pins the current version by hash.
Depth against successor, once the package is confirmed stalled
Registry rules: when Adopt is actually on the table
Adopt means getting publish rights on the original name, and only PyPI offers a third-party route to that. Everywhere else, the current owner has to agree. If the owner is the person who stopped answering, Adopt is not available.
| Registry | Third-party transfer of an abandoned name? | Wait or contact rule | Fork evidence |
|---|---|---|---|
| PyPI | Yes, under PEP 541 | 3 attempts, 6 weeks | Required |
| npm | No mediation since Feb 2021 | n/a | n/a |
| crates.io | No, owner approval only | n/a | Advice is to pick a new name |
| RubyGems | Ownership calls and requests (2021) | Unverified | Unverified |
The details that change your week:
- PyPI (PEP 541). A project counts as abandoned only when the owner cannot be reached, there has been no release in twelve months, and the owner shows no activity on the project's home page. Admins try at least three times and stop trying after six weeks. You must show your own failed attempts to contact the owner, show improvements made on your own fork, and explain why publishing the fork under a different name is not acceptable. Requests go through the public pypi/support tracker.
- npm. npm ran a four-week mediation process and suspended it in February 2021 after a mis-transfer.
- crates.io. crates.io will not transfer an existing crate without the explicit approval of the current owner. Its advice is to ask the owner directly or pick a new name.
- RubyGems. RubyGems has offered ownership calls and requests since the end of 2021. I could not verify the wait times or evidence it requires, so check its current documentation before planning around it.
This matches what the research found. The rescuers in Avelino et al.'s study named two barriers: lack of time, and the difficulty of getting push access. Registry policy has since made push access harder to get, not easier. So in practice, "Adopt" means "Fork under a new name" on every registry except PyPI, unless the owner answers.
Finding a successor or a rescuer
When nobody is maintaining the package, the successor question is about people: is anyone, besides you, positioned to keep it alive? Most abandoned projects never find that person. Most of those that do find exactly one.
What happens to abandoned projects
- 1,932Projects studied
Avelino et al., GitHub
- 315Abandoned
16% of the sample
- 128Survived via new core developers
41% of the abandoned
- 86% of survivorsRescued by a single new developer
Bus factor still 1
Even when you find a rescuer, they may not be enough. Fork and Adopt verdicts often fail on staffing rather than code: one engineer patches the fork, then changes teams, and the package is quiet again. If your verdict is Fork or Adopt, the second maintainer is part of the verdict, not a nice-to-have. That person might be an existing contributor to the fork, someone who has filed a PEP 541 request for a related package, or a hire with maintainer history.
Finding those people by hand means reading commit graphs, fork networks, and support trackers, and then working out who each handle belongs to. Refolk does that from a plain-English request across the public GitHub graph, LinkedIn, and the open web. It returns the people behind the commits with their current roles, so you can tell a credible co-maintainer from a drive-by contributor.
Where the rescuer pool is thin
The talent pool is not the same everywhere. In Refolk's index of professional profiles, the two keywords people tend to search for this job give very different results by country.
| Keyword | US | Germany | US:DE multiple |
|---|---|---|---|
| open source maintainer | 123 | 47 | 2.6x |
| software supply chain security | 230 | 15 | 15.3x |
| Maintainer : supply-chain ratio | 0.53 | 3.1 | n/a |
All counts come from Refolk's index. The multiples and ratios are derived from them.
What this means for sourcing:
- Search by maintainer titles, not "supply chain security". In Refolk's index, the US supply-chain results skew toward sales and Field CISO titles. Chainguard is the top US employer in that set, at 6 of a 25-profile sample.
- Outside the US, start from maintainer communities. The German supply-chain set has only 15 profiles, though it includes an OWASP Dependency-Track Project Co-Lead. The US maintainer set includes a "Lead Maintainer AboutCode and Scancode". People maintaining tooling like that know which forks are real.
Step-by-step: scoring one stalled package in a week
The procedure takes about two working days of effort spread across the week, and most of that is evidence gathering. The durations below are my desk estimates, not measured figures. One change from the obvious order: contact the maintainer on day one, because every reply window starts from that message.
Score one stalled dependency
- Confirm the symptomPull the last release date, last commit date, Scorecard Maintained result, registry status marker, and GitHub archived flag into a dated evidence sheet. About an hour.
- Contact the maintainer and start the clockSend one specific message through the project's channel and one other public channel, and log the date and channel. On PyPI this record is required evidence for any later PEP 541 request.
- Separate finished from deadRead the open issues for unanswered bug or CVE reports and check whether the code depends on a moving platform API, then score A. About two hours.
- Score exposureCheck open advisories against the exact lockfile version and reproduce any open bugs, then score E, taking 2 unless you can prove the vulnerable path is unused. About an hour.
- Measure integration depthFind where the package's calls and types appear and whether another dependency pulls it in, then score D. About half a day.
- Look for successorsCheck forks with releases, new committers on the original repo, handoff notes, and deprecation notices, and read each candidate's registry owners list, then score S. About two hours.
- Score takeover riskCount owners, check WHOIS expiry on maintainer email domains, and note the publish method and registry credential controls, then score T on the weakest layer. About an hour.
- Record the verdict and a dated review triggerApply the six ordered rules and the takeover overlay, and write one verdict, an owner, a review date, and the events that pull the review earlier.
When the issue tracker has gone silent, the maintainer often still works somewhere and reads mail there. Refolk can find their current profile and employer from the commit history, so step 2 reaches a channel they actually read. Keep the message short and give them easy options, including the one where they do nothing more than hand over the keys.
Subject: <package name>: still maintained? Offer to help or take over Hi <maintainer name>, I work at <company>, where we ship <package name> <version> in production. I've noticed there have been no releases since <date> and that <issue link> and <issue link> are open without a reply. I'd like to help rather than fork quietly. Any one of these would work for us: 1. You add <name> and <name> as co-maintainers with publish rights. 2. You hand over the package and repository to us. 3. You mark the project archived or deprecated and point to a successor, so downstream users know. 4. You tell us it is finished and the open issues are not bugs, and we will leave it alone. If I don't hear back by <date>, we will publish a patched fork under a new name and link it from an issue here. Thank you for the work you put into this. <name>, <role>, <contact>
Send through the project's own channel first, keep a copy, and log the date; edit the options to match what you would actually accept.
Package: <name> Version in lockfile: <version> Registry: <PyPI / npm / crates.io / RubyGems / other> Scored by: <name> Date: <YYYY-MM-DD> A Abandonment confidence (0/1/2): <score> Last release: <date> Last commit: <date> Scorecard Maintained: <result> Registry status: <status> Repo archived: <yes/no> Unanswered bug or CVE issues: <links> Maintainer contacted: <date, channel, reply or none> E Exposure (0/1/2): <score> Advisories against shipped version: <links> Unused-path proof: <link or none> D Integration depth (0/1/2): <score> Where calls and types appear: <modules> Pulled in transitively by: <packages or none> S Successor availability (0/1/2): <score> Candidate: <name and link> Releases: <yes/no> People with publish rights: <count> T Takeover risk (0/1/2): <score> Owners: <count, last activity> Email domain WHOIS expiry: <dates> Publish method: <token / trusted publishing / unknown> Registry credential controls: <confirmed / unconfirmed> Rule matched (1-6): <rule> Verdict: <Adopt / Fork / Replace / Contain> Takeover overlay: <applied or not; pinned version and hash> Review date: <YYYY-MM-DD> Earlier if: <events> Owner of the verdict: <name>
One record per package; every score needs a link and the date you checked it.
How this goes wrong: false dead, false alive, and false safety
Most bad verdicts come from trusting one signal that looks decisive and is not. These eight failure modes cover the common ones. Each comes with the check that catches it.
- Scorecard Maintained = 0 on a finished library (false dead). A small, stable utility scores as unmaintained and gets forked or replaced for no reason. Check: are any bug or CVE issues actually unanswered, and does the code depend on a platform API that keeps changing? If neither, score A = 1 and contain it. Scorecard's own documentation uses the is-even library as its example of this.
- A partial Maintained score from bot or triage activity (false alive). Labels, stale-bot comments, and volunteers closing duplicates all count as issue activity. Check: did a release or merged fix ship in the window? If not, the project is not maintained in any sense that helps you.
- Reading "no archived marker" as active. Only 6 of about 145 known-obsolete PyPI projects checked carried the marker. Check: score A from releases, fixes, and owner replies. Markers can only raise the score.
- Waiting for an end-of-life notice. Fewer than 5% of abandoned npm packages clearly announce one. Check: treat silence as the signal and decide on the week's evidence.
- Assuming a PEP 541 takeover fits a one-week decision. PyPI's contact window is six weeks, and npm and crates.io offer no equivalent route. Check: if the owner has not granted publish rights in writing by the decision date, rule 4 fails and the verdict is Fork or another rule's outcome.
- Scoring takeover risk low because two-factor authentication exists. Accounts recovered through a resurrected email domain are exposed if they lack MFA. Check: look up the WHOIS expiry of each maintainer email domain. An expired or near-expiry domain scores T = 2 whatever the registry's MFA policy says.
- Treating a single rescuer as a successor. 86% of rescues in Avelino et al.'s study depended on one person, so the bus factor stays at one. Check: count the people with publish rights on the candidate. One person scores S = 1, which does not trigger Replace.
- Sourcing rescuers with the keyword "supply chain security". In Refolk's index, the US results skew toward sales and Field CISO titles, and the German pool is 15 profiles. Check: filter by maintainer titles and actual commit history, not security-sounding job titles.
Two of these mistakes cost the most. A false dead (1) wastes a quarter on a migration nobody needed. False safety (6) leaves a hijackable publish path in your build. When the evidence is ambiguous on either, the "unproven safety scores as risk" rule exists for exactly that case.
Keeping the verdict current
A verdict on a stalled dependency is a dated judgement, not a permanent state. Every record needs a review date and a short list of events that pull the review forward.
Default review triggers by verdict:
- Contain: 90 days from the verdict, matching Scorecard's window. Review sooner on any new advisory against the pinned version, any platform or runtime change the package touches, or any new release. When T = 2, a new release from a dormant account is itself a warning sign.
- Fork: 90 days after your fork's first release. Check that your own fork would now score A = 0. Review sooner if upstream activity resumes. On PyPI, add a trigger six weeks after filing the PEP 541 request.
- Replace: the migration due date. The job is done when the package no longer appears in your lockfile, including as a transitive dependency.
- Adopt: 90 days after takeover. You now own a package other people depend on, so score it the way they would. If it would score A = 2, you have recreated the problem.
If you run a status-aware tool such as uv audit or Composer's abandoned-package policy, feed it the verdicts so a later status change shows up without anyone having to remember. Don't let the tool replace the review date, for the same reason markers cannot drive the score: they depend on the maintainer acting.
Before you call the verdict done
- Every one of the five scores has a linked artifact and the date it was checked.
- The maintainer contact message was sent, and its date and channel are logged.
- Exposure was checked against the exact version in the lockfile, not the latest release.
- Integration depth names whether any other shipped dependency pulls the package in transitively.
- The successor candidate's registry owners list was read and the number of publishers recorded.
- Maintainer email domains were checked for WHOIS expiry.
- The rule number that produced the verdict is written down, and rules 1 to 6 were applied in order.
- If T scored 2, the package is pinned by exact version and integrity hash in every lockfile.
- The record has a named owner, a review date, and the events that pull the review earlier.
- A second engineer has scored the package independently and matched the verdict, or the disagreement is resolved in the record.
The last item is the test of the whole standard. If two engineers scoring the same package from the same public evidence reach different verdicts, one of the anchors was applied without its artifact. Find that score, attach the evidence, and re-run the rules.
Questions practitioners ask
How do I tell if an open source library is abandoned or just finished?
Look for unanswered bug or security reports, not for a quiet commit log. A library with no recent commits but nothing unanswered, and no dependence on a moving platform API, is finished and should be contained and left alone. It is abandoned when real reports sit unanswered and nobody with publish rights responds. OpenSSF Scorecard's Maintained check cannot make this distinction on its own; its documentation says small utilities may not need maintenance at all.
What should I do with an unmaintained package that has an open CVE?
Pin it by exact version and integrity hash today, then score it. An open advisory against the version you ship, with the vulnerable path not ruled out, scores Exposure 2. With a credible maintained successor the verdict is Replace; without one it is Fork, so you can ship the patch under your own name. Contain is only available if you can prove the vulnerable code is never reached and you attach that proof to the record.
Can I take over maintenance of an abandoned package on npm or crates.io?
Not without the current owner's agreement. npm suspended its name-transfer mediation in February 2021 after a mis-transfer, and crates.io will not transfer an existing crate without explicit approval from the current owner. If the owner hands over publish rights, you can adopt. If they do not answer, your practical options are forking under a new name, replacing the package, or containing it.
How long does a PEP 541 name transfer on PyPI take?
Longer than a one-week decision. PyPI admins try to reach the owner at least three times and stop trying after six weeks, and the requester must show their own failed contact attempts, improvements made on their own fork, and why a different name will not work. Publish your fork under a new name first, file the request, and set the review trigger six weeks after filing.
The dependency maintainer is not responding. How long should I wait before deciding?
Do not let the wait set your schedule. Send the contact message on day one, score the other four dimensions while you wait, and decide on the evidence you have at the end of the week. If a handoff arrives later, it shows up as a review trigger: a Fork can turn into an Adopt. Silence is the normal case, since fewer than 5% of abandoned npm packages clearly announce end of life.
Is a community fork a safe successor?
Only if it has published releases and more than one person holds publish rights. In Avelino et al.'s study, 86% of rescued projects depended on a single new developer, which leaves the bus factor at one. A fork run by one person scores Successor availability 1, not 2, and it does not trigger a Replace verdict. Check its registry owners list and release history before you migrate to it.
Try it on the search you came here for
Stop building boolean strings. Just describe the person.
Type one sentence. I plan the search, read GitHub, public LinkedIn and Crunchbase records, and the open web as it is right now, and hand back a ranked list with the reason next to every name.
01Describe them
One plain sentence. Role, city, stack, stage, whatever matters to you.
02I read the web live
GitHub, public LinkedIn and Crunchbase records, the open web. Not a database that went stale last quarter.
03You read the shortlist
Ranked, with the reasoning under every name. Open a profile, ask a follow-up, narrow it down.
- Staff backend engineers in NYC who shipped Rust in production
- Series A fintechs in SF under 50 people, growing headcount this year
- Maintainers of fast-growing Rust web frameworks on GitHub
- No boolean, no filters, no seat to buy. One box.
- Read at search time, so a profile updated yesterday counts today.
- Every step visible as it runs, every name with its reason.
500 free credits on sign-up. No card, no demo call. See real searches.