How to Build a Link Preview API with Node.js and ToolCenter
Introduction
Link previews are everywhere — Slack, Discord, Twitter, WhatsApp. When you paste a URL, these platforms automatically fetch the page title, description, and image to create a rich preview card.
Building this yourself means dealing with HTML parsing, Open Graph tags, Twitter Cards, favicon extraction, and handling edge cases. Or you can use an API.
In this tutorial, we'll build a link preview service using Node.js and the ToolCenter Link Preview API.
Prerequisites
- Node.js 18+
- A ToolCenter API key (get one free)
- Basic JavaScript knowledge
Install the SDK
npm install toolcenter
Quick Start
import ToolCenter from "toolcenter";
const tc = new ToolCenter("your-api-key");
const preview = await tc.linkPreview({
url: "https://github.com"
});
console.log(preview);
// {
// title: "GitHub: Let's build from here",
// description: "GitHub is where over 100 million developers...",
// image: "https://github.githubassets.com/images/...",
// favicon: "https://github.githubassets.com/favicons/favicon.svg",
// domain: "github.com"
// }
Building a Complete Service
Let's create an Express server that generates link previews on demand:
import express from "express";
import ToolCenter from "toolcenter";
const app = express();
const tc = new ToolCenter(process.env.TOOLCENTER_API_KEY);
app.get("/preview", async (req, res) => {
const { url } = req.query;
if (!url) {
return res.status(400).json({ error: "URL is required" });
}
try {
const preview = await tc.linkPreview({ url });
res.json(preview);
} catch (error) {
res.status(500).json({ error: error.message });
}
});
app.listen(3000, () => {
console.log("Link preview service running on port 3000");
});
Adding Caching
For production, you'll want to cache results to avoid redundant API calls:
const cache = new Map();
const CACHE_TTL = 3600000; // 1 hour
app.get("/preview", async (req, res) => {
const { url } = req.query;
const cached = cache.get(url);
if (cached && Date.now() - cached.timestamp < CACHE_TTL) {
return res.json(cached.data);
}
try {
const preview = await tc.linkPreview({ url });
cache.set(url, { data: preview, timestamp: Date.now() });
res.json(preview);
} catch (error) {
res.status(500).json({ error: error.message });
}
});
Combining with Other APIs
ToolCenter's power is in combining multiple APIs. Let's enrich our preview with a favicon:
app.get("/rich-preview", async (req, res) => {
const { url } = req.query;
const [preview, favicon] = await Promise.all([
tc.linkPreview({ url }),
tc.favicon({ url }),
]);
res.json({
...preview,
favicons: favicon,
});
});
Error Handling
Always handle potential errors gracefully:
try {
const preview = await tc.linkPreview({ url });
return preview;
} catch (error) {
if (error.status === 429) {
await new Promise(r => setTimeout(r, 1000));
return tc.linkPreview({ url });
}
return {
title: new URL(url).hostname,
description: null,
image: null,
url
};
}
Pricing
The ToolCenter Free plan includes 100 API calls per month — enough to build and test your service. The Pro plan (€9/month) gives you 10,000 calls, and Business (€29/month) gives 50,000.
Conclusion
With ToolCenter's Link Preview API and the Node.js SDK, you can build a production-ready link preview service in under 50 lines of code. No HTML parsing, no edge cases, no maintenance.
Get started: Create a free account and start building!
This tutorial uses the ToolCenter Node.js SDK. Also available for Python and PHP.