DEV Community

Cover image for Enhancing Link Shortener App with Google Gemini
Henry Lim
Henry Lim

Posted on

Enhancing Link Shortener App with Google Gemini

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:


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 });
Enter fullscreen mode Exit fullscreen mode

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;
};
Enter fullscreen mode Exit fullscreen mode

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);
};
Enter fullscreen mode Exit fullscreen mode

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;
};
Enter fullscreen mode Exit fullscreen mode
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);
};
Enter fullscreen mode Exit fullscreen mode

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}`);
});
Enter fullscreen mode Exit fullscreen mode

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" }
};
Enter fullscreen mode Exit fullscreen mode

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)

Collapse
 
thanir03 profile image
Thanirmalai

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