Verified community node: three eligibility questions before a zero-dependency rewrite

Hi n8n team,

I maintain n8n-nodes-duckduckgo-search, a credential-free DuckDuckGo search node with roughly 21,000 installs. I would like to submit it for verification and have read the requirements, the zero-runtime-dependency rule in particular. Meeting it means removing four dependencies — axios, duck-duck-scrape, @mozilla/readability and linkedom. The last two power the node’s article-text extraction, and replacing them is a substantial rewrite with a real risk of quality regression.

Before committing to that work, three things I could not settle from the documentation:
1. “Must not be an existing node.” There is no DuckDuckGo node in n8n today, and this package already has ~21k installs, so I read the rule as not applying here. Is that right, or does it also cover a community node that already exists?

2. Unofficial endpoints. DuckDuckGo publishes no search API. The node uses the same HTML/lite endpoints and the public Instant Answer API that every DuckDuckGo library uses. The guidelines do not address unofficial endpoints either way. Is a node built on them eligible for verification at all? If not, I would rather know before starting.

3. Review from a datacenter IP. DuckDuckGo rate-limits per IP and answers a burst with an anomaly page — HTTP 202 carrying a CAPTCHA, not an error status. A reviewer testing from cloud infrastructure will very likely hit it. The node detects that page and reports it explicitly rather than returning an empty list, so what a reviewer would see is an error message instead of search results. Is there a way to flag this ahead of a review, or a preferred way to demonstrate that the node works?

Information on the package

Thanks,
Sam Nodehi

Hey @Sam_Nodehi, while you wait for a response, here are some things that might help:

Suggested resources

Automatically matched to your question.

Docs:

Forum:

@Misha, @Baseman - you’ve helped with similar issues before, can you take a look?

Automatically suggested by n8n’s community bot. It’s a pilot - please share feedback here.

I went through verification recently so some of this may transfer, but would double check with the n8n team. Treat this as one maintainer’s reading rather than a ruling.

On the dependency rule, the thing I would settle before committing to a rewrite is whether bundling counts. The constraint is on what npm resolves and installs at runtime, so vendoring your dependencies into the published dist with a bundler may satisfy it without removing any functionality. If that reading holds, readability and linkedom stay where they are and you skip the regression risk entirely. That is the difference between a build config change and a rewrite, so it is worth asking explicitly rather than assuming it either way.

Personally, we removed all external deps to get verified and just made it use our APIs server side. One downside is that for our popular package GitHub - TurboDocx/html-to-docx: HTML to DOCX converter · GitHub, we would need to burn compute cycles on this and likely put it in our metered plan.

On question 3, the datacenter IP problem: the fact that your node detects the anomaly page and reports it explicitly instead of returning an empty array is the correct behaviour, and I would put that near the top of the readme rather than leaving a reviewer to discover it. A reviewer who hits the rate limit and sees a clear “DuckDuckGo returned an anomaly page” message is watching your error handling work, which is a very different impression from a node that appears to return nothing. Said up front, it reads as robustness. Said after the fact, it reads as an excuse.

On question 1, I read it the way you do. “Must not be an existing node” has always looked to me like it means an existing first party node, since the whole verification path exists for community packages. Also - not sure if you can get a node in that you don’t work for the company? But that is a reading, not a confirmation, and it is exactly the kind of thing worth getting in writing before you spend the effort.

Thanks, this was worth chasing, because if bundling counted it would change the whole decision. I went and measured it rather than reasoning about it, and the answer turns out to be “yes, but not for these libraries”.

You are right about the dependencies field. n8n’s own rule documentation says so explicitly, no-runtime-dependencies.md:

Shared libraries must be declared in peerDependencies (so the host runtime supplies them) or bundled at build time into the published artifact.

And no-restricted-imports.md exempts anything in devDependencies, on the grounds that it is never installed at runtime. So moving the libraries to devDependencies and bundling them into dist does clear both of those rules.

The part that decides it is that the scan has two legs. From the comment in scanner/scanner.mjs in @n8n/scan-community-package@0.35.0:

The .ts globs only ever match the provenance-attested source checkout, the tarball leg lints compiled .js and the published package.json only.

So the bundle itself gets linted, and no-restricted-globals, no-dangerous-functions and no-console apply to whatever the bundler emitted.

Measured, not assumed. I bundled exactly my three problem dependencies, axios, @mozilla/readability, linkedom, with esbuild (1.1 MB output), then ran n8n’s own scan config over it via the scanner’s analyzePackage:

passed: false
✖ 125 problems (125 errors, 0 warnings)

The breakdown: process ×46, globalThis ×8, setTimeout ×15, clearTimeout ×9, setImmediate ×5, console. ×11. No eval or new Function, for what it’s worth. And one category I had not expected, Node built-ins are blocked too:

error  Require of 'stream' is not allowed. n8n Cloud does not allow community nodes with dependencies
error  Require of 'util' is not allowed.
error  Require of 'path' is not allowed.

So bundling is a real option in general, it depends entirely on what the library’s own code contains, but it does not rescue anything built on the Node platform surface, which is most HTTP clients and every DOM implementation. For my case it is removal, not a build-config change, which is the conclusion I was hoping to avoid.

That also matches what the team told another maintainer in an earlier thread: remove all external deps, including the ones n8n’s own nodes use.

Two other things, in case they are useful to anyone reading:

The provenance requirement is straightforward once set up, a trusted publisher on npm plus id-token: write, no token anywhere. One trap: trusted publishers have an Allowed actions setting that can be registered as npm stage publish only, which fails with E403 OIDC permission denied for this action after provenance has already been signed. And it needs npm ≥ 11.5.1, while actions/setup-node with Node 22 still ships npm 10.

There is also a bug worth flagging: on Windows the scanner’s source-fetch leg dies with a mangled temp path (tar: C\:\\Users\\...: Cannot open), so only the provenance check completes. A Windows maintainer cannot run the full scan locally.

On question 3, I took your advice straight away. The anomaly-page handling is now the first thing in the README, above the feature list, saying what an empty result set does and does not mean. Your framing was exactly right, and while writing it I found the guarantee was not actually true on one path: image search checked for the challenge on the token bootstrap request but not on the request that carries the results, so a block there still returned an empty array. Fixed and tested. So thank you twice.

On question 1, that is my reading too. Your second point is the one I had not considered, whether n8n accepts a node for a service you have no affiliation with. Adding that to what I would like confirmed.

@Sam_Nodehi
@Nicolas_Fry weldone !.. I’d also clarify the endpoint question before doing the rewrite. Since DuckDuckGo doesn’t provide an official search API, the reviewer’s test environment could be just as important as the node itself. For the datacenter/IP issue, I agree that explicitly documenting the 202 response and anomaly handling in the README is a good move. It gives the reviewer context instead of making a failed test look like a broken node.

And for the dependency reqirement , I’d definitely get confirmation from n8n on whether bundling/vendoring is acceptable before removing readability and linkedom - that could save a lot of unnecessary rewrite work .

Thanks @daniel_Samuel, and you are right to push on the bundling question even after I posted the measurement, because the measurement answers a narrower question than it looks like it does.

What I established is what the scanner does: bundle axios, @mozilla/readability and linkedom with esbuild, run @n8n/scan-community-package’s own config over the output, and you get 125 errors. All of them come from the libraries’ own code, process ×46, globalThis ×8, setTimeout ×15, plus require('stream'), require('util'), require('path').

What it does not establish is whether that verdict is the policy. process inside a bundled dependency is not the node “using a restricted global” in any sense a person would recognise, nobody wrote it, it is not reachable from the node’s own surface, and the rule it trips exists to stop nodes doing things on n8n Cloud rather than to stop a dependency existing. A reviewer could reasonably read it either way, and only n8n can say which.

So I think the question to put to them is sharper than “is bundling acceptable”, which their own rule documentation already answers, no-runtime-dependencies says shared libraries “must be declared in peerDependencies … or bundled at build time into the published artifact”, and no-restricted-imports exempts anything in devDependencies. Between them, moving the libraries to devDependencies and bundling clears both of those rules cleanly. The open question is the leg after that:

Does the scan’s verdict on vendored third-party code bind, or can a reviewer waive findings that come from a bundled dependency rather than from the node’s own source?

If it binds, the answer for this node is a genuine rewrite and I would rather know that before starting it. If a reviewer can waive it, the same node ships with a build config change and no risk to the extraction quality, which is the difference you and Nicolas were both pointing at.

On the other two, agreed and already done. The 202 and anomaly handling is now the first thing in the README, above the feature list, saying what an empty result set does and does not mean, your framing of “context for the reviewer instead of a failed test looking like a broken node” is exactly why. Writing it also turned up a real bug: image search checked for the anomaly page on the request that fetches the token but not on the one that returns results, so a block there still came back as an empty list. Fixed, along with the same gap on the 403 path.

Still no word from anyone at n8n on the thread. If nothing arrives this week I will take the same three questions to nodes@n8n.io and report back here either way, since the answer is not really specific to DuckDuckGo, anyone whose node needs an HTML parser or an HTTP client is standing in front of the same wall.

Update: version 32.17.0 is out. Extract Page Content and Fetch Page Content now read the first 2 MB of large pages instead of failing. The page timeout now covers the whole download. Extraction runs in a worker thread, so a page that is very slow to parse can no longer freeze n8n.

Two templates built on the node are now in the library: