https://g.co/gemini/share/d454b8a4977b
To build a secure static website on Firebase that uses the Gemini API, you need to solve one specific problem: hiding your API Key.
Since a static site runs entirely in the user’s browser, any API key you put in your JavaScript code is visible to anyone who views the “Source.” The standard solution is to use Firebase Cloud Functions as a middleman (proxy).
Here is the architecture we will build:
Prerequisites
* Node.js & npm installed.
* Google Cloud Account (for Firebase).
* Gemini API Key from Google AI Studio.
Step 1: Initialize the Firebase Project
Open your terminal and create a new directory for your project.
mkdir gemini-static-site
cd gemini-static-site
npm install -g firebase-tools
firebase login
Initialize the project. When asked for features, select Hosting and Functions.
firebase init
* Project: Create a new project (e.g., gemini-web-demo).
* Language: JavaScript (for this tutorial).
* ESLint: No (to keep it simple).
* Dependencies: Yes (install them now).
* Public directory: public (default).
* Single-page app: No.
* GitHub builds: No.
Step 2: Create the Backend (Cloud Function)
This function will run on Google’s servers. It will hold your API key, receive the prompt from your website, talk to Gemini, and return the answer.
* Navigate to the functions folder:
cd functions
* Install the Google Generative AI SDK:
npm install @google/genai
* Open functions/index.js and replace the code with this:
<!– end list –>
const { onRequest } = require(“firebase-functions/v2/https”);
const { GoogleGenAI } = require(“@google/genai”);
// Initialize Gemini with your key (stored in environment variables for security)
const genAI = new GoogleGenAI({ apiKey: process.env.GEMINI_API_KEY });
exports.askGemini = onRequest({ cors: true }, async (req, res) => {
// 1. Validate the request
const userPrompt = req.body.prompt;
if (!userPrompt) {
return res.status(400).send({ error: “No prompt provided” });
}
try {
// 2. Call the Gemini API
const model = genAI.getGenerativeModel({ model: “gemini-1.5-flash” });
const result = await model.generateContent(userPrompt);
const response = await result.response;
const text = response.text();
// 3. Send result back to frontend
res.json({ answer: text });
} catch (error) {
console.error(“Error calling Gemini:”, error);
res.status(500).send({ error: “Failed to generate content” });
}
});
Step 3: Configure the API Key
Never hardcode secrets. We will set the API key in the Firebase environment configuration.
Run this command in your terminal (replace YOUR_ACTUAL_API_KEY with your real key):
firebase functions:secrets:set GEMINI_API_KEY
# Paste your key when prompted
Note: You may need to upgrade your Firebase project to the “Blaze” (Pay-as-you-go) plan to use Cloud Functions and Secrets. It usually has a generous free tier.
Step 4: Create the Frontend
Go back to the root directory and open public/index.html. Replace the content with this simple interface:
<!DOCTYPE html>
<html lang=”en”>
<head>
<meta charset=”UTF-8″>
<meta name=”viewport” content=”width=device-width, initial-scale=1.0″>
<title>Gemini Static Site</title>
<style>
body { font-family: sans-serif; max-width: 600px; margin: 2rem auto; padding: 0 1rem; }
textarea { width: 100%; height: 100px; margin-bottom: 1rem; padding: 10px; }
button { padding: 10px 20px; background: #007bff; color: white; border: none; cursor: pointer; }
button:disabled { background: #ccc; }
#response { margin-top: 20px; white-space: pre-wrap; background: #f4f4f4; padding: 15px; border-radius: 5px; }
</style>
</head>
<body>
<h1>Ask Gemini</h1>
<textarea id=”promptInput” placeholder=”Type your question here…”></textarea>
<button id=”askBtn” onclick=”sendPrompt()”>Ask Gemini</button>
<div id=”response”></div>
<script>
async function sendPrompt() {
const prompt = document.getElementById(‘promptInput’).value;
const output = document.getElementById(‘response’);
const btn = document.getElementById(‘askBtn’);
if (!prompt) return;
// UI Loading State
output.textContent = “Thinking…”;
btn.disabled = true;
try {
// Replace PROJECT_ID and REGION with your actual values after first deploy
// Or use the relative path if serving locally
const functionUrl = ‘/askGemini’;
const req = await fetch(functionUrl, {
method: ‘POST’,
headers: { ‘Content-Type’: ‘application/json’ },
body: JSON.stringify({ prompt: prompt })
});
const data = await req.json();
output.textContent = data.answer || data.error;
} catch (err) {
output.textContent = “Error: ” + err.message;
} finally {
btn.disabled = false;
}
}
</script>
</body>
</html>
Step 5: Connect Frontend to Backend (Rewrites)
To make fetch(‘/askGemini’) work seamlessly without worrying about CORS or full URLs, configure a rewrite in firebase.json.
Open firebase.json and ensure it looks like this:
{
“hosting”: {
“public”: “public”,
“ignore”: [
“firebase.json”,
“**/.*”,
“**/node_modules/**”
],
“rewrites”: [
{
“source”: “/askGemini”,
“function”: “askGemini”
}
]
},
“functions”: [
{
“source”: “functions”,
“codebase”: “default”,
“ignore”: [
“node_modules”,
“.git”,
“firebase-debug.log”,
“firebase-debug.*.log”
]
}
]
}
Step 6: Test and Deploy
1. Local Testing:
Firebase can emulate both hosting and functions locally so you can test before deploying.
firebase emulators:start
Open the localhost URL provided in the terminal (usually http://localhost:5000).
2. Deploy to Live:
firebase deploy
Next Step: Would you like me to show you how to add streaming responses (so the text appears as it is being generated) or how to add image upload capabilities?
Leave a comment