You can build a Node.js link checker that validates a submitted URL, checks it with Google Safe Browsing and VirusTotal, and reports each provider’s result separately. The title’s “three API calls” is not supported by the documented integrations here: Safe Browsing URL lookup is one call, while VirusTotal requires a scan submission and a follow-up analysis request. Those three calls use two providers, not three. A clean result means no known match was returned—not that a URL is proven safe.
Before you build: provider limits and URL privacy
Google Safe Browsing checks URLs against Google-maintained lists of unsafe resources, including phishing and other social-engineering threats. Google states, “The Safe Browsing APIs are for non-commercial use only,” and points commercial malicious-URL detection to Web Risk. Review Web Risk’s current terms and configuration if your use is commercial.
As an Amazon Associate I earn from qualifying purchases.
The direct Safe Browsing URL lookup sends the submitted URL to Google. Google also documents a hash-prefix approach that reduces disclosure, but it requires canonicalizing and hashing the URL, expanding suffixes and prefixes, and comparing results. VirusTotal warns that indicators submitted or queried through its API are scanned and added to its community-accessible dataset. Do not send it sensitive, confidential, or personally identifiable URLs; check its current API and data-use terms before production use.
Do these 3 things before closing this tab:
1Clear out junk files and repair common Windows errors2Fix the driver behind crashes, sound loss and screen glitches3Repair Windows errors before they cause bigger problemsFor a first implementation, the direct Safe Browsing lookup is simpler. Its endpoint permits up to 50 URLs per request, though this example checks one. The response includes a threats list and cacheDuration; an HTTP 200 response with an empty threat list means only that no known match was returned. Honor the returned cache duration when caching results.
#1 Best Overall
- POWERFUL SECURITY KEY: The Security Key C NFC is the essential physical passkey for protecting your digital life from phishing attacks. It ensures only you can access your accounts.
- WORKS WITH 1000+ ACCOUNTS: Compatible with Google, Microsoft, and Apple. A single Security Key C NFC secures 100 of your favorite accounts, including email, password managers, and more.
- FAST & CONVENIENT LOGIN: Plug in your Security Key C NFC via USB-C and tap it, or tap it against your phone (NFC) to authenticate. No batteries, no internet connection, and no extra fees required.
- TRUSTED PASSKEY TECHNOLOGY: Uses the latest passkey standards (FIDO2/WebAuthn & FIDO U2F) but does not support One-Time Passwords. For complex needs, check out the YubiKey 5 Series.
- BUILT TO LAST: Made from tough, waterproof, and crush-resistant materials. Manufactured in Sweden and programmed in the USA with the highest security standards.
Set up a server-side Node.js endpoint
Keep API keys on the server, not in browser JavaScript. This example uses Node.js with Express and the built-in fetch API (Node.js 18 or later). Install Express with npm install express, then set SAFE_BROWSING_API_KEY and VIRUSTOTAL_API_KEY in the server environment. Do not commit the keys to source control.
The route validates URL syntax and accepts only HTTP and HTTPS. It never fetches the submitted destination: querying reputation services is different from opening the URL. Fetching user-supplied destinations introduces server-side request forgery and redirect risks that this checker does not address.
Rank #2
- POWERFUL SECURITY KEY: The YubiKey 5C NFC is the most versatile physical passkey, protecting your digital life from phishing attacks. It ensures only you can access your accounts
- WORKS WITH 1000+ ACCOUNTS: Compatible with popular accounts like Google, Microsoft, and Apple. A single YubiKey 5C NFC secures 100+ of your favorite accounts, including email, password managers, and more
- FAST & CONVENIENT LOGIN: Plug in your YubiKey 5C NFC via USB and tap it, or tap it against your phone (NFC), to authenticate. No batteries, no internet connection, and no extra fees required
- MOST SECURE PASSKEY: Supports FIDO2/WebAuthn, FIDO U2F, Yubico OTP, OATH-TOTP/HOTP, Smart card (PIV), and OpenPGP. That means it’s versatile, working almost anywhere you need it
- PRIMARY & SPARE KEYS: Just like having a spare house key, we recommend buying two YubiKeys - one for daily use and one as a spare. That way you’ll never get locked out of your accounts
import express from "express";
const app = express();
app.use(express.json({ limit: "8kb" }));
const SAFE_BROWSING_API_KEY = process.env.SAFE_BROWSING_API_KEY;
const VIRUSTOTAL_API_KEY = process.env.VIRUSTOTAL_API_KEY;
function parseHttpUrl(value) {
if (typeof value !== "string" || value.length > 2048) {
throw new Error("Enter a URL no longer than 2048 characters.");
}
let parsed;
try {
parsed = new URL(value);
} catch {
throw new Error("Enter a valid absolute URL, including https:// or http://.");
}
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
throw new Error("Only HTTP and HTTPS URLs are accepted.");
}
return parsed.href;
}
async function fetchWithTimeout(url, options = {}, timeoutMs = 8000) {
const controller = new AbortController();
const timer = setTimeout(() => controller.abort(), timeoutMs);
try {
return await fetch(url, { ...options, signal: controller.signal });
} finally {
clearTimeout(timer);
}
}
async function checkSafeBrowsing(url) {
if (!SAFE_BROWSING_API_KEY) {
return { provider: "Google Safe Browsing", status: "error", error: "Provider is not configured." };
}
try {
const response = await fetchWithTimeout(
`https://safebrowsing.googleapis.com/v5/urls:search?key=${encodeURIComponent(SAFE_BROWSING_API_KEY)}`,
{
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({
urls: [url],
threatTypes: ["SOCIAL_ENGINEERING", "MALWARE"],
client: { clientId: "example-link-checker", clientVersion: "1.0" }
})
}
);
if (!response.ok) throw new Error(`Provider returned HTTP ${response.status}.`);
const data = await response.json();
return {
provider: "Google Safe Browsing",
status: data.threats?.length ? "match" : "no_known_match",
threats: data.threats ?? [],
cacheDuration: data.cacheDuration ?? null
};
} catch (error) {
return { provider: "Google Safe Browsing", status: "error", error: error.name === "AbortError" ? "Request timed out." : error.message };
}
}
async function checkVirusTotal(url) {
if (!VIRUSTOTAL_API_KEY) {
return { provider: "VirusTotal", status: "error", error: "Provider is not configured." };
}
try {
const submitted = await fetchWithTimeout("https://www.virustotal.com/api/v3/urls", {
method: "POST",
headers: { "x-apikey": VIRUSTOTAL_API_KEY, "content-type": "application/x-www-form-urlencoded" },
body: new URLSearchParams({ url })
});
if (!submitted.ok) throw new Error(`Scan submission returned HTTP ${submitted.status}.`);
const submission = await submitted.json();
const analysisId = submission.data?.id;
if (!analysisId) throw new Error("Provider did not return an analysis ID.");
const analysisResponse = await fetchWithTimeout(
`https://www.virustotal.com/api/v3/analyses/${encodeURIComponent(analysisId)}`,
{ headers: { "x-apikey": VIRUSTOTAL_API_KEY } }
);
if (!analysisResponse.ok) throw new Error(`Analysis retrieval returned HTTP ${analysisResponse.status}.`);
const analysis = await analysisResponse.json();
const attributes = analysis.data?.attributes ?? {};
const stats = attributes.stats ?? {};
const detections = (stats.malicious ?? 0) + (stats.suspicious ?? 0);
return {
provider: "VirusTotal",
status: attributes.status === "completed" ? (detections ? "match" : "no_known_match") : "pending",
analysisId,
stats
};
} catch (error) {
return { provider: "VirusTotal", status: "error", error: error.name === "AbortError" ? "Request timed out." : error.message };
}
}
app.post("/api/check-link", async (req, res) => {
let url;
try {
url = parseHttpUrl(req.body?.url);
} catch (error) {
return res.status(400).json({ error: error.message });
}
const results = await Promise.all([checkSafeBrowsing(url), checkVirusTotal(url)]);
res.json({ url, results });
});
app.listen(3000, () => console.log("Listening on http://localhost:3000"));
The route makes three provider calls in total: one Safe Browsing lookup, then VirusTotal scan submission and analysis retrieval. VirusTotal analysis may still be pending when retrieved; in that case the response preserves that state rather than treating it as a clean result.
Quick wins for a faster PC:
Scan for outdated or missing drivers - takes under a minuteDriver Scan →Clear out junk files and repair common Windows errorsFree Scan →Send a URL and read the response
With the server running and both keys configured, send JSON to the route:
Rank #3
- POWERFUL SECURITY KEY: The YubiKey 5 NFC is the most versatile physical passkey, protecting your digital life from phishing attacks. It ensures only you can access your accounts
- WORKS WITH 1000+ ACCOUNTS: Compatible with popular accounts like Google, Microsoft, and Apple. A single YubiKey 5 NFC secures 100+ of your favorite accounts, including email, password managers, and more
- FAST & CONVENIENT LOGIN: Plug in your YubiKey 5 NFC via USB and tap it, or tap it against your phone (NFC), to authenticate. No batteries, no internet connection, and no extra fees required
- MOST SECURE PASSKEY: Supports FIDO2/WebAuthn, FIDO U2F, Yubico OTP, OATH-TOTP/HOTP, Smart card (PIV), and OpenPGP. That means it’s versatile, working almost anywhere you need it
- PRIMARY & SPARE KEYS: Just like having a spare house key, we recommend buying two YubiKeys - one for daily use and one as a spare. That way you’ll never get locked out of your accounts
curl -X POST http://localhost:3000/api/check-link
-H 'content-type: application/json'
-d '{"url":"https://example.com/"}'
The result contains a separate object for each provider. A match is evidence that the provider reported a finding; no_known_match means no match was reported in that response; pending means VirusTotal has not completed the analysis; and error records a failed or unavailable check. Preserve categories and provider errors in the user interface rather than collapsing them into an unexplained score.
Handle results without overstating safety
- One or more matches: show the provider and its reported category, and advise the user not to open the link unless they can verify it through a trusted channel.
- No known match from both: say that neither provider returned a known match. Coverage, freshness, and the providers’ findings are not a guarantee that the destination is safe.
- Providers disagree: show the disagreement clearly and advise caution instead of averaging the results into a reassuring score.
- Pending or error: identify which provider did not return a completed result. Do not present a partial check as a clean bill of health.
For Safe Browsing, use the returned cacheDuration when caching its response rather than choosing an arbitrary lifetime. Add rate limits and request-size controls to a public endpoint, and avoid logging submitted URLs if they may contain private information.
Rank #4
- POWERFUL SECURITY KEY: The Security Key NFC is the essential physical passkey for protecting your digital life from phishing attacks. It ensures only you can access your accounts.
- WORKS WITH 1000+ ACCOUNTS: Compatible with Google, Microsoft, and Apple. A single Security Key NFC secures 100 of your favorite accounts, including email, password managers, and more.
- FAST & CONVENIENT LOGIN: Plug in your Security Key NFC via USB-A and tap it, or tap it against your phone (NFC) to authenticate. No batteries, no internet connection, and no extra fees required.
- TRUSTED PASSKEY TECHNOLOGY: Uses the latest passkey standards (FIDO2/WebAuthn & FIDO U2F) but does not support One-Time Passwords. For complex needs, check out the YubiKey 5 Series.
- BUILT TO LAST: Made from tough, waterproof, and crush-resistant materials. Manufactured in Sweden and programmed in the USA with the highest security standards.
When to use the hash-prefix lookup
Google’s v5 documentation provides urls.search for sending actual URLs and hashes.search for requests based on four-byte hash prefixes. The URL method is easier to implement but exposes the raw queried URL to Google. Hash-prefix matching reduces that disclosure, at the cost of canonicalization, hashing, suffix/prefix expansion, and local comparison logic. Choose it when URL confidentiality matters enough to justify the extra implementation work; it does not remove VirusTotal’s separate community-dataset disclosure if you also submit the URL there.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Official API references
- Google Safe Browsing v5 overview
- Google Safe Browsing
urls.searchreference - VirusTotal Scan URL reference
Provider documentation and terms can change; verify current API behavior and use conditions before deploying.
Quick Recap
Best Value
- Security Key : Protect your online accounts against unauthorized access by using FIDO2 and U2F authentication with T110. It's the world's most protective security key that works with windows, Mac OS, Linux as well as Chrome, Firefox, Edge and many other major browsers.
- Certified with the new FIDO2 standard, T110 provides the benefit of fast login and strong protection against phishing, account takeover as well as many other online attactks.
- Works with : Bank of America, Github, Google, Microsoft, DUO, Twitter, Facebook, Dropbox, Apple, ebay, BINANCE, mor and more.
- Fits USB-A port : Insert the T110 security key into the USB-A port of each service and log in conveniently with one touch
- For the driver download and user guide, please visit TrustKey Solutions Home support page.
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.




