In this article, we'll learn how to enhance a link shortener app with Google Gemini. We will use Node.js and Express for our backend, Gemini to generate an easy-to-remember short link, and Puppeteer to extract useful context from web pages.
What We'll Learn Today:
- How to set up the Google Gen AI JS/TS SDK
- How to use Gemini to generate text output
- How to generate structured output (JSON) with Gemini
- How to use Puppeteer to get a page title
- Bonus: How to run Gemini Nano on Chrome locally
1: Set Up Google Gen AI SDK
First, install the @google/genai
JS/TS SDK by running npm install @google/genai
.
Next, you'll need to get your Gemini API Key from https://aistudio.google.com/apikey.
It's always good practice not to expose the API key on the client side; therefore, we'll run the code on the server side (Node.js).
import { GoogleGenAI, Type } from "@google/genai";
const GEMINI_API_KEY = process.env.GEMINI_API_KEY;
const ai = new GoogleGenAI({ apiKey: GEMINI_API_KEY });
2: Text Generation with Gemini
Now that we've set up the Google Gen AI SDK, it's time to write the prompt. Google has an excellent guide on how to write the most efficient prompts: https://ai.google.dev/gemini-api/docs/prompting-strategies.
Here is our prompt to generate the short link:
You are a link shortener application. Your task is to generate a concise, human-readable, unique, compact, memorable short URL.
Only use lowercase, replace spaces with hyphens, and avoid special characters. Only return the URL slug, do not include the domain.Shorten to URL for "https://blog.google/products/photos/updates-ask-photos-search/"
We will select gemini-2.5-flash
as our model, and provide the contents and system instruction to Gemini by calling the generateContent
function:
export const generateShortUrl = async (longUrl) => {
const response = await ai.models.generateContent({
model: "gemini-2.5-flash",
contents:
'Shorten to URL for "https://blog.google/products/photos/updates-ask-photos-search/"',
config: {
systemInstruction:
"You are a link shortener application. Your task is to generate a concise, human-readable, unique, compact, memorable short URL. Only use lowercase, replace spaces with hyphens, and avoid special characters. Only return the URL slug, do not include the domain.",
},
});
return response.text;
};
3. Structured Output
By default, the SDK returns unstructured text. While this is useful for building chatbots, it's not ideal for automating the short link generation process.
Fortunately, you can configure Gemini to return structured output, ensuring consistent and predictable results.
export const generateShortUrl = async (longUrl) => {
const response = await ai.models.generateContent({
model: "gemini-2.5-flash",
contents: `Shorten to url for "https://blog.google/products/photos/updates-ask-photos-search/"`,
config: {
systemInstruction:
"You are an URL shortener application. Your task is to generate a concise, human-readable, unique, compact, memorable short URL.",
responseMimeType: "application/json",
responseSchema: {
type: Type.OBJECT,
properties: {
shortUrl: {
type: Type.STRING,
description:
"Only use lowercase, replace spaces with hyphens, and avoid special characters. Only return the URL slug, do not include the domain.",
},
},
required: ["shortUrl"],
},
},
});
return JSON.parse(response.text);
};
In this case, the output will look like this: { "shortUrl": "google-photos-search" }
.
4. Providing More Context with Puppeteer
Currently, we're only providing Gemini with the page URL. Sometimes, URLs can be very abstract, like "https://www.bbc.com/news/articles/cpw77qwd117o".
In such cases, Gemini won't be able to generate a meaningful short link unless we provide more context, such as the page title.
We can use Puppeteer to scrape the page title and send it to Gemini.
export const getMetadata = async (longUrl, title) => {
const browser = await puppeteer.launch({ headless: "new" });
const page = await browser.newPage();
await page.goto(longUrl, { waitUntil: "domcontentloaded", timeout: 15000 });
const metadata = await page.evaluate(() => {
return {
title: document.title || null,
};
});
await browser.close();
return metadata;
};
export const generateShortUrl = async (longUrl, title) => {
const response = await ai.models.generateContent({
model: "gemini-2.5-flash",
contents: `Shorten to url for "${longUrl}". The page title is ${title}`,
// ...
});
return JSON.parse(response.text);
};
In this case, Gemini will return { "shortUrl": "ai-chatbot-google-search" }
instead of { "shortUrl": "cpw77qwd117o" }
.
5. Create an API Endpoint with Express
Now that we have all the functions ready, we can create an Express server and expose our function via an API endpoint so it can be accessible from the frontend.
import express from "express";
import { generateShortUrl } from "./src/gemini.js";
import { getMetadata } from "./src/puppeteer.js";
const app = express();
const PORT = process.env.PORT || 3000;
// Middleware to parse JSON
app.use(express.json());
// Endpoint to generate short link
app.post("/generateShortUrl", async (req, res) => {
const { longUrl } = req.query;
const title = getMetadata(longUrl);
const shortUrl = await generateShortUrl(longUrl, title);
res.json(shortUrl);
});
// Start the server
app.listen(PORT, () => {
console.log(`Server running on http://localhost:${PORT}`);
});
Bonus: Run Gemini Nano on Chrome Locally
Chrome is currently experimenting with the ability to run Gemini Nano locally. The Prompt API is currently still in the Early Preview Program (EPP) and is not production-ready at the moment. You can learn how to set it up here: https://developer.chrome.com/docs/ai/get-started.
Currently, it's nice to have the ability to run Gemini Nano locally, but make sure you have provided a cloud-based solution as a fallback.
export const generateShortUrl = async (longLink, title) => {
const session = await LanguageModel.create({
initialPrompt: [
{
role: "system",
content:
"You are an URL shortener application. Your task is to generate a concise, human-readable, unique, compact, memorable short URL.",
},
],
});
const prompt = `Shorten to url for "${longLink}". The page title is ${title}`;
const result = await session.prompt(prompt, {
responseConstraint: {
shortUrl: {
type: "string",
description:
"Only use lowercase, replace spaces with hyphens, and avoid special characters. Only return the URL slug, do not include the domain.",
},
},
});
return JSON.parse(result); // { shortUrl: "example-short-url" }
};
Conclusion
In this article, we explored how to build a link shortener using Node.js and Express, enhancing it with AI using Google Gemini.
We learned how to set up the Google Gen AI SDK, how to write a prompt to generate text output, and how to use structured output to generate JSON responses. We also learned how to use Puppeteer to extract more context, like page titles, which improves the relevance and meaningfulness of the generated short links. As a bonus, we also learned how to generate text content locally with Gemini Nano on Chrome.
Top comments (1)
Interesting approach but I think there’s a critical architecture problem here. AI-generated slugs can't guarantee uniqueness. Since Gemini doesn't have access to your backend storage or existing slugs, there's a real risk of collisions