Build and Deploy an AI-Powered Website
Build a live AI chat website using Cursor, Git, and the Claude API.
Introduction
30 Second Summary
Every time you ask an AI a question on a website, there's code behind the scenes connecting your message to an AI model and sending the answer back. What if you could build one of those sites yourself?
In this project, you will build and deploy a personal webpage with a working AI chat feature powered by the Claude API. You'll write code with AI assistance, track your changes with Git, and ship a live site that anyone on the internet can visit.
What You'll Build
A styled personal webpage with an "Ask Claude" feature that sends user questions to the Claude API via a serverless function, deployed live on Netlify.
By the end of this project, you'll have:
- A styled webpage with an interactive AI chat section where visitors can ask questions and get answers from Claude.
- A Git repository pushed to GitHub with multiple commits showing your progress through the project.
- A live deployed site on Netlify with a serverless function that securely calls the Claude API.
- Secret Mission: Add conversation memory so Claude remembers previous messages in the same session.
Are there any prerequisites?
You'll need a GitHub account before starting. If you don't have one yet, sign up for free at github.com. Everything else (Git, Cursor, Netlify, and your API key) gets set up during the project.
Install Git and Cursor
Before you can build anything, you need the right tools on your machine. Git tracks every change you make to your code, so you can always undo mistakes and share your work on GitHub.
Cursor is your code editor for this project. It's built on VS Code but has AI features baked in, so you can ask it questions and get help writing code without leaving the editor.
In this step, get ready to:
- Install and verify Git on your machine.
- Configure Git with your GitHub identity.
- Install Cursor, your AI-powered code editor.
Install Git
Git is the version control system that will track your code changes and let you push them to GitHub. You'll run all Git commands from your terminal (also called the command line).
- Press Cmd+Space (macOS) or the Windows key (Windows) to open your search bar.
- Type Terminal (macOS) or PowerShell (Windows) and press Enter to open it.
What is a terminal?
A terminal is a text-based interface where you type commands instead of clicking buttons. Developers use it to install tools, run scripts, and manage files.
Now check if Git is already installed on your machine.
- Check your Git installation by running this command:
git --version
✔️ I see a version number
You should see something like git version 2.54.0. Git is ready to go. Skip ahead to the next substep.
ⓧ macOS asked me to install Command Line Tools
On macOS, running git --version for the first time triggers a dialog asking to install Xcode Command Line Tools. This includes Git.
- Click Install in the dialog that appears.
- Wait for the installation to finish (this may take a few minutes).
- Run git --version again to confirm it installed successfully.
ⓧ Command not found
Git is not installed yet. Follow the instructions for your operating system below.
macOS
- Install Git by running this command:
xcode-select --install
- Click Install in the dialog that appears.
- Wait for the installation to complete.
- Run git --version to confirm Git is now available.
Windows
- Install Git by running this command in PowerShell:
winget install --id Git.Git -e --source winget
- Close your PowerShell window completely.
- Open a new PowerShell window (the PATH update only takes effect in new windows).
- Run git --version to confirm Git is now available.
Still not seeing a version number?
On Windows, make sure you closed and reopened PowerShell after running the install command. The git command won't work in the same window where you ran the installer.
If winget doesn't work, download the installer directly from git-scm.com and run it with all default settings.
Help me troubleshoot my Git installation
Configure Git with your GitHub details
Git needs to know who you are so it can label each change you make with your name. You'll set this to match the username and email on your GitHub account.
- Set your Git username by running this command:
git config --global user.name "[[GITHUB_USERNAME="your GitHub username"]]"
- Set your Git email by running this command:
git config --global user.email "[[GITHUB_EMAIL="your GitHub email address"]]"
What does global mean here?
The --global flag means this setting applies to every Git project on your computer. You only need to do this once.
- Confirm your settings saved correctly by running:
git config --global --list
You should see your user.name and user.email listed in the output.
Don't see your name or email in the output?
Make sure you included the quotes around your username and email when running the commands. Try running the git config commands again with your values in double quotes.
Help me fix my Git config
Install Cursor
Cursor is the code editor you'll use for the rest of this project. It looks and works like VS Code, but has built-in AI chat and code generation features.
- Open your browser and go to cursor.com.
- Click the download button for your operating system (macOS or Windows).
- Run the installer once the download finishes.
- Sign up for the free Hobby plan when prompted. No credit card is required.
What does the Hobby plan include?
The free Hobby plan gives you 2,000 tab completions and 50 AI chat requests per month. That's more than enough for this project.
- Press Cmd+Space (macOS) or the Windows key (Windows) to open your search bar.
- Type Cursor and press Enter to open it.
You should see the Cursor editor open with a welcome tab or an empty workspace.
Cursor won't open or isn't found?
If your search bar doesn't find Cursor, the installation may not have completed. Try opening the downloaded installer file again.
On macOS, make sure you dragged Cursor into your Applications folder if the installer asked you to.
Help me get Cursor working
Your tools are installed and ready. Next up, you'll create a project on GitHub and start building your website inside Cursor.
Set Up Your Project and GitHub Repository
Your tools are installed and ready to go. Now it's time to create the project that will hold all your code.
Every professional project starts with a repository on GitHub. A repository is a folder that tracks every change you make to your code over time. You'll create one on GitHub, clone it to your computer, and set up the files you'll need for your AI website.
In this step, get ready to:
- Create a GitHub repository and clone it to your computer.
- Open the project in Cursor and explore its AI features.
- Create the file structure for your website and serverless function.
Create a GitHub repository and clone it
A GitHub repository gives your project a home on the internet. It also lets services like Netlify automatically deploy your site whenever you push new code.
- Go to github.com and sign in to your account.
- Click the + icon in the top-right corner of any page.
- Select New repository from the dropdown menu.
- Enter ai-website in the Repository name field.
- Keep the visibility set to Public.
- Check the box for Add a README file.
- Click Create repository.
Why add a README file?
Checking this box creates an initial commit in your repository. Without it, the repository would be completely empty and you wouldn't be able to clone it in the next step.
GitHub takes you to your new repository page. You'll see a green Code button near the top.
- Click the green Code button.
- Make sure HTTPS is selected in the tab bar.
- Click the copy icon next to the URL to copy it to your clipboard.
Now open your terminal to clone this repository to your computer.
- Open your terminal by pressing Cmd+Space (macOS) or the Windows key (Windows) and typing Terminal (macOS) or PowerShell (Windows), then press Enter.
- Move to your Desktop by running this command:
cd ~/Desktop
- Clone your repository by running this command:
git clone https://github.com/[[GITHUB_USERNAME="your-github-username"]]/ai-website.git
What does this command do?
The git clone command downloads a copy of your GitHub repository to your computer. It creates a new folder called ai-website on your Desktop with the repository's contents inside.
- Move into your new project folder by running:
cd ai-website
- Confirm the clone worked by running:
ls
You should see README.md listed in the output.
Getting a 'repository not found' error?
Double-check that the URL you copied matches your GitHub username and the repository name ai-website. Make sure the repository visibility is set to Public.
If you're still stuck, help me fix this git clone error.
Open your project in Cursor
With the repository on your computer, open it in Cursor so you can start building.
- Open Cursor (it should already be running from Step 1).
- Click File in the top menu bar.
- Click Open Folder.
- Navigate to your Desktop, select the ai-website folder, then click Open.
You should see the ai-website folder name in the Explorer sidebar on the left, with README.md listed inside it.
What makes Cursor different from a regular code editor?
Cursor is built on VS Code, so it has the same editor features you'd find there. The difference is that Cursor has built-in AI that can write and edit code for you.
Two features to know about for this project:
- Inline edit (Cmd+K on macOS, Ctrl+K on Windows): Highlight code and ask AI to change it.
- Chat panel (Cmd+L on macOS, Ctrl+L on Windows): Ask questions about your code or get AI to generate new code.
You'll use both of these features in the next step when building your webpage.
Create the project file structure
Your project needs four files and one directory. The HTML, CSS, and JavaScript files make up your website's frontend. The netlify/functions/ directory is where your serverless function will live.
- Open Cursor's integrated terminal by pressing Ctrl+` (backtick key, located above Tab on your keyboard).
Windows users: select Git Bash
If your terminal opens as PowerShell, click the dropdown arrow next to the + icon in the terminal panel and select Git Bash. This ensures the file-creation commands below work correctly.
- Create the three frontend files by running this command:
touch index.html style.css script.js
- Create the serverless functions directory by running:
mkdir -p netlify/functions
What does mkdir -p do?
The -p flag tells mkdir to create parent directories as needed. Since the netlify folder doesn't exist yet, this one command creates both netlify/ and functions/ inside it.
- Confirm all files and folders were created by running:
ls
You should see index.html, style.css, script.js, netlify, and README.md in the output.
Look at the Explorer sidebar in Cursor. It should update automatically to show all the new files and the netlify/functions folder.
Don't see the files in Cursor's sidebar?
Try clicking somewhere in the Explorer sidebar to refresh it. If the files still don't appear, make sure you opened the ai-website folder (not a parent folder) in Cursor.
If you see a different set of files than expected, help me figure out why my file structure looks wrong.
Your project structure is ready and your repository is connected to GitHub. Next up, you'll use Cursor's AI features to write the HTML and CSS for your webpage.
Build Your Webpage with Cursor's Help
Your project folder is set up and open in Cursor. Now it's time to build the actual webpage that visitors will see and interact with.
In this step, you'll use Cursor's AI features to help write your HTML and CSS code, then save your progress using Git.
In this step, get ready to:
- Write the HTML structure for your webpage using Cursor's AI chat.
- Style the page with CSS to make it look polished.
- Make your first Git commit to save your progress.
Write the HTML using Cursor's AI chat
Cursor has a built-in AI chat panel that can generate code for you. You describe what you want, and it writes the code.
- Open Cursor's chat panel by pressing Cmd+Shift+L (macOS) or Ctrl+Shift+L (Windows).
- Type a prompt like this into the chat:
Create an HTML page with: a header showing "My AI Website" and "Powered by Claude", a main section with an h2 "Ask Claude Anything", a response area div, a text input for questions, and an Ask button. Include a footer that says "Built with Cursor, Git, and Claude API". Link to style.css and script.js.
Why use AI to write code?
Cursor's AI can generate boilerplate code quickly so you can focus on understanding the structure rather than memorizing syntax. The AI might produce slightly different output each time, so you'll double-check the result against the code provided below.
- Open index.html in Cursor's editor by clicking it in the Explorer sidebar on the left.
- Replace everything in the file with the following HTML:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>My AI Website</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<header>
<h1>My AI Website</h1>
<p>Powered by Claude</p>
</header>
<main>
<section class="chat-section">
<h2>Ask Claude Anything</h2>
<div class="chat-container">
<div id="response-area" class="response-area">
<p class="placeholder">Claude's answer will appear here...</p>
</div>
<div class="input-area">
<input type="text" id="question-input" placeholder="Type your question..." />
<button id="ask-button">Ask</button>
</div>
</div>
</section>
</main>
<footer>
<p>Built with Cursor, Git, and Claude API</p>
</footer>
<script src="script.js"></script>
</body>
</html>
What does this HTML do?
- The <header> displays your site title and tagline at the top of the page.
- The chat-section contains the main interactive area where users type questions and see Claude's answers.
- The id attributes (like response-area and question-input) give JavaScript a way to find and update these elements later.
- The <script src="script.js"> tag at the bottom loads your JavaScript file after the page content is ready.
- Save index.html by pressing Cmd+S (macOS) or Ctrl+S (Windows).
- Right-click index.html in the Explorer sidebar and select Reveal in Finder (macOS) or Reveal in File Explorer (Windows), then double-click the file to open it in your browser.
- You should see your page title "My AI Website", the "Ask Claude Anything" heading, a text input field, and an Ask button. It won't be styled yet.
Seeing a blank page?
- Make sure you saved the file. Unsaved files show a dot on the tab name in Cursor.
- Check that you opened index.html directly in the browser (the URL should start with file://).
- Verify the file isn't empty. If it is, paste the HTML code above into it and save again.
Help me debug why my HTML page is blank in the browser.
Style the page with CSS
Your HTML gives the page structure, but CSS makes it visually appealing. You'll add styles that create a clean, modern layout.
- Open style.css in Cursor's editor.
- Paste the following page layout styles into the file:
/* Reset default browser spacing */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
/* Page-wide layout and font */
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
line-height: 1.6;
color: #333;
max-width: 800px;
margin: 0 auto;
padding: 20px;
background-color: #f5f5f5;
}
/* Header title area */
header {
text-align: center;
padding: 40px 0;
}
header h1 {
font-size: 2.5rem;
color: #1a1a2e;
}
header p {
color: #666;
margin-top: 8px;
}
/* Footer at the bottom */
footer {
text-align: center;
padding: 30px 0;
color: #666;
}
What does this CSS do?
- The * reset removes all default browser margins and padding so your design starts from a clean slate.
- The max-width: 800px and margin: 0 auto on the body centers your content and keeps lines from stretching too wide on large screens.
- The header and footer styles center text and add breathing room with padding.
- Save style.css and refresh your browser.
- You should see your page title centered at the top with a light grey background. The text uses a clean system font instead of the browser default.
Styles not showing up?
- Check that your HTML has <link rel="stylesheet" href="style.css"> in the <head> section.
- Make sure style.css is in the same folder as index.html (both at the top level of ai-website).
- Try a hard refresh: Cmd+Shift+R (macOS) or Ctrl+Shift+R (Windows).
Help me figure out why my CSS isn't being applied to my HTML page.
- Now add the chat section styles below the footer styles in style.css:
/* White card for the chat section */
.chat-section {
background: white;
border-radius: 12px;
padding: 30px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
}
.chat-section h2 {
margin-bottom: 20px;
color: #1a1a2e;
}
/* Area where Claude's response appears */
.response-area {
min-height: 150px;
padding: 20px;
background: #f9f9f9;
border-radius: 8px;
margin-bottom: 16px;
white-space: pre-wrap;
}
.response-area .placeholder {
color: #999;
font-style: italic;
}
/* Input and button row */
.input-area {
display: flex;
gap: 10px;
}
/* Text input field */
#question-input {
flex: 1;
padding: 12px 16px;
border: 2px solid #e0e0e0;
border-radius: 8px;
font-size: 1rem;
outline: none;
transition: border-color 0.2s;
}
#question-input:focus {
border-color: #4a90d9;
}
/* Ask button */
#ask-button {
padding: 12px 24px;
background-color: #4a90d9;
color: white;
border: none;
border-radius: 8px;
font-size: 1rem;
cursor: pointer;
transition: background-color 0.2s;
}
#ask-button:hover {
background-color: #357abd;
}
#ask-button:disabled {
background-color: #ccc;
cursor: not-allowed;
}
What do these styles do?
- The .chat-section styles create a white card with rounded corners and a subtle shadow, making the interactive area stand out from the background.
- The display: flex on .input-area places the text input and button side by side.
- The :focus, :hover, and :disabled states change the appearance when a user interacts with the input and button.
- Save style.css and refresh your browser.
- You should see a white card with rounded corners, a grey response area showing placeholder text, and a blue Ask button next to the text input.
Chat section doesn't look like a card?
- Make sure the second chunk of CSS was pasted below (not replacing) the first chunk you added.
- Check for missing closing braces }. Each CSS rule block needs an opening and closing brace.
Help me fix my CSS for the chat section card styling.
✔️ Awesome, I've got everything!
Great. Double check you've saved both files before moving on.
ⓧ I'd like to double check the full code
Here's the complete style.css file. Make sure yours matches:
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
line-height: 1.6;
color: #333;
max-width: 800px;
margin: 0 auto;
padding: 20px;
background-color: #f5f5f5;
}
header {
text-align: center;
padding: 40px 0;
}
header h1 {
font-size: 2.5rem;
color: #1a1a2e;
}
header p {
color: #666;
margin-top: 8px;
}
.chat-section {
background: white;
border-radius: 12px;
padding: 30px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
}
.chat-section h2 {
margin-bottom: 20px;
color: #1a1a2e;
}
.response-area {
min-height: 150px;
padding: 20px;
background: #f9f9f9;
border-radius: 8px;
margin-bottom: 16px;
white-space: pre-wrap;
}
.response-area .placeholder {
color: #999;
font-style: italic;
}
.input-area {
display: flex;
gap: 10px;
}
#question-input {
flex: 1;
padding: 12px 16px;
border: 2px solid #e0e0e0;
border-radius: 8px;
font-size: 1rem;
outline: none;
transition: border-color 0.2s;
}
#question-input:focus {
border-color: #4a90d9;
}
#ask-button {
padding: 12px 24px;
background-color: #4a90d9;
color: white;
border: none;
border-radius: 8px;
font-size: 1rem;
cursor: pointer;
transition: background-color 0.2s;
}
#ask-button:hover {
background-color: #357abd;
}
#ask-button:disabled {
background-color: #ccc;
cursor: not-allowed;
}
footer {
text-align: center;
padding: 30px 0;
color: #666;
}
Make your first Git commit
A Git commit is like a snapshot of your project at a specific point in time. If something breaks later, you can always return to this snapshot.
- Open the integrated terminal in Cursor by pressing Ctrl+` (backtick key, located above Tab on most keyboards).
- Stage all your changes by running this command:
git add .
- Create your first commit with a descriptive message by running:
git commit -m "Add homepage HTML and CSS"
What do these commands do?
- git add . stages every changed file in your project folder. The dot means "everything in the current directory."
- git commit -m saves a permanent snapshot with a message describing what changed. Future commits build on this one, creating a timeline of your project.
- Verify your commit was saved by running:
git log --oneline
- You should see one line with a short commit ID followed by Add homepage HTML and CSS.
Seeing "nothing to commit"?
- Make sure you saved both index.html and style.css before running git add ..
- Confirm your terminal is inside the ai-website folder by running pwd. You should see a path ending in /ai-website.
Help me figure out why Git says there's nothing to commit.
Your webpage is built, styled, and saved in Git. Next up, you'll connect to the Claude API and build the serverless function that powers the AI feature.
Create the Serverless Function and Connect the Claude API
Your webpage has a styled layout with an input field and button, but clicking Ask does nothing yet. The missing piece is the backend logic that connects your button to Claude's brain.
In this step, you'll create a serverless function that securely calls the Claude API. You'll also write the JavaScript that wires your page's button to that function.
In this step, get ready to:
- Get your free Anthropic API key.
- Build a serverless function that calls the Claude API.
- Write frontend JavaScript to connect the button to your function.
Get your Anthropic API key
Your serverless function needs an API key to authenticate with Claude. Anthropic gives new accounts approximately $5 in free credits with no credit card required.
- Open platform.claude.com in your browser.
- Click Sign Up and create a free account using your email or Google account.
- Once signed in, click API Keys in the left sidebar.
- Click Create Key.
- Give the key a name like ai-website and click Create Key.
- Copy the key that appears and paste it somewhere safe (like a notes app). You will not be able to see it again.
What is an API key?
An API key is like a password that lets your code talk to another service. Your serverless function will send this key to Anthropic's servers to prove it has permission to use Claude.
Your key starts with sk-ant-. Keep it secret. Never paste it directly into frontend code that browsers can see.
Create the serverless function
Your API key must stay secret, so you cannot call Claude directly from browser JavaScript. Instead, you'll create a serverless function that runs on Netlify's servers and keeps the key hidden.
What is a serverless function?
A serverless function is a small piece of code that runs on someone else's server only when it's needed. You don't manage any server yourself. Netlify automatically runs your function whenever your website sends a request to it.
- In Cursor's Explorer sidebar, expand the netlify/functions/ folder.
- Create a new file inside it called ask-claude.mjs.
Why the .mjs extension?
The .mjs extension tells Netlify this file uses the modern ES module format. This lets you use export default syntax instead of the older module.exports pattern.
- Add the function shell with request validation by pasting this code into ask-claude.mjs:
export default async (req, context) => {
// Only allow POST requests
if (req.method !== "POST") {
return new Response(JSON.stringify({ error: "Method not allowed" }), {
status: 405,
headers: { "Content-Type": "application/json" },
});
}
// Extract the question from the request body
const { question } = await req.json();
// Return an error if no question was provided
if (!question) {
return new Response(JSON.stringify({ error: "No question provided" }), {
status: 400,
headers: { "Content-Type": "application/json" },
});
}
};
What does this code do?
This is the outer shell of your serverless function. It receives incoming web requests and validates them before doing any real work.
- export default async (req, context) defines the function Netlify will run when your site receives a request.
- The first if block rejects anything that is not a POST request (like someone visiting the URL directly in a browser).
- The second if block rejects requests that don't include a question in the body.
- Now add the Claude API call. Find the closing line that says:
if (!question) {
return new Response(JSON.stringify({ error: "No question provided" }), {
status: 400,
headers: { "Content-Type": "application/json" },
});
}
};
- Replace the closing }; with the API call code below, so the function continues after the validation:
// Get the API key from Netlify's environment variables
const apiKey = Netlify.env.get("ANTHROPIC_API_KEY");
// Send the question to Claude's API
const apiResponse = await fetch("https://api.anthropic.com/v1/messages", {
method: "POST",
headers: {
"Content-Type": "application/json",
"x-api-key": apiKey,
"anthropic-version": "2023-06-01",
},
body: JSON.stringify({
model: "claude-haiku-4-5",
max_tokens: 1024,
messages: [{ role: "user", content: question }],
}),
});
// Parse Claude's response
const result = await apiResponse.json();
// Extract the text answer from the response
const answer = result.content?.[0]?.text || "No response from Claude.";
// Send the answer back to the browser
return new Response(JSON.stringify({ answer: answer }), {
status: 200,
headers: { "Content-Type": "application/json" },
});
};
What does this code do?
This is where the magic happens. Your function retrieves the API key, sends the user's question to Claude, and returns the answer.
- Netlify.env.get("ANTHROPIC_API_KEY") reads your secret key from Netlify's secure environment variables (not from your code).
- The fetch call sends a POST request to Claude's API endpoint with the required headers and your question.
- claude-haiku-4-5 is the model name for Claude's fastest and cheapest model.
- result.content?.[0]?.text safely extracts Claude's text answer from the API response.
- Save ask-claude.mjs.
Seeing red squiggly lines in Cursor?
Cursor may show a warning about Netlify being undefined. That is expected. The Netlify global object only exists when the function runs on Netlify's servers, not in your local editor.
If you see other errors, make sure the opening export default async (req, context) => { and closing }; are present and match.
help me fix errors in my ask-claude.mjs serverless function
✔️ Awesome, I've got everything!
Great. Double check you've saved your file before moving on.
ⓧ I'd like to double check the full code
export default async (req, context) => {
if (req.method !== "POST") {
return new Response(JSON.stringify({ error: "Method not allowed" }), {
status: 405,
headers: { "Content-Type": "application/json" },
});
}
const { question } = await req.json();
if (!question) {
return new Response(JSON.stringify({ error: "No question provided" }), {
status: 400,
headers: { "Content-Type": "application/json" },
});
}
const apiKey = Netlify.env.get("ANTHROPIC_API_KEY");
const apiResponse = await fetch("https://api.anthropic.com/v1/messages", {
method: "POST",
headers: {
"Content-Type": "application/json",
"x-api-key": apiKey,
"anthropic-version": "2023-06-01",
},
body: JSON.stringify({
model: "claude-haiku-4-5",
max_tokens: 1024,
messages: [{ role: "user", content: question }],
}),
});
const result = await apiResponse.json();
const answer = result.content?.[0]?.text || "No response from Claude.";
return new Response(JSON.stringify({ answer: answer }), {
status: 200,
headers: { "Content-Type": "application/json" },
});
};
Write the frontend JavaScript
Your serverless function is ready to receive questions and return answers. Now you need the browser-side code that captures what the user types, sends it to your function, and displays Claude's response on the page.
- Open script.js in Cursor (it should be empty).
- Add the DOM references and event listeners by pasting this code:
// Grab references to the HTML elements we need
const questionInput = document.getElementById("question-input");
const askButton = document.getElementById("ask-button");
const responseArea = document.getElementById("response-area");
// Call askClaude when the button is clicked
askButton.addEventListener("click", askClaude);
// Also call askClaude when the user presses Enter
questionInput.addEventListener("keydown", function (event) {
if (event.key === "Enter") {
askClaude();
}
});
What does this code do?
- document.getElementById() grabs each HTML element by its id attribute so you can interact with it in code.
- addEventListener("click", askClaude) tells the browser to run the askClaude function whenever the button is clicked.
- The keydown listener lets users press Enter instead of clicking the button.
- Now add the askClaude function below the event listeners:
async function askClaude() {
// Get the user's question and remove extra whitespace
const question = questionInput.value.trim();
if (!question) return;
// Disable the button and show a loading state
askButton.disabled = true;
askButton.textContent = "Thinking...";
responseArea.innerHTML = "<p>Asking Claude...</p>";
try {
// Send the question to our serverless function
const response = await fetch("/.netlify/functions/ask-claude", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ question: question }),
});
const data = await response.json();
// Display the answer or an error message
if (data.answer) {
responseArea.innerHTML = "<p>" + data.answer + "</p>";
} else {
responseArea.innerHTML = "<p>Something went wrong. Please try again.</p>";
}
} catch (error) {
responseArea.innerHTML = "<p>Error connecting to Claude. Please try again.</p>";
}
// Reset the button and clear the input
askButton.disabled = false;
askButton.textContent = "Ask";
questionInput.value = "";
}
What does this code do?
This function handles the full lifecycle of asking Claude a question.
- It first disables the button and shows "Thinking..." so the user knows something is happening.
- fetch("/.netlify/functions/ask-claude") sends the question to your serverless function (which then calls Claude).
- The try/catch block handles network errors gracefully instead of crashing the page.
- After the response arrives, it re-enables the button and clears the input for the next question.
- Save script.js.
You will not be able to test this locally yet because the serverless function only runs on Netlify's servers. In the next step, you'll deploy everything and test it live.
Cursor showing an error on askClaude?
Make sure the event listeners (which reference askClaude) appear ABOVE the function definition in the same file. JavaScript hoists function declarations, so this works correctly at runtime even though the call appears first.
If you see other errors, check that all opening braces { have a matching closing brace }.
help me fix errors in my script.js file
✔️ Awesome, I've got everything!
Great. Double check you've saved your file before moving on.
ⓧ I'd like to double check the full code
const questionInput = document.getElementById("question-input");
const askButton = document.getElementById("ask-button");
const responseArea = document.getElementById("response-area");
askButton.addEventListener("click", askClaude);
questionInput.addEventListener("keydown", function (event) {
if (event.key === "Enter") {
askClaude();
}
});
async function askClaude() {
const question = questionInput.value.trim();
if (!question) return;
askButton.disabled = true;
askButton.textContent = "Thinking...";
responseArea.innerHTML = "<p>Asking Claude...</p>";
try {
const response = await fetch("/.netlify/functions/ask-claude", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ question: question }),
});
const data = await response.json();
if (data.answer) {
responseArea.innerHTML = "<p>" + data.answer + "</p>";
} else {
responseArea.innerHTML = "<p>Something went wrong. Please try again.</p>";
}
} catch (error) {
responseArea.innerHTML = "<p>Error connecting to Claude. Please try again.</p>";
}
askButton.disabled = false;
askButton.textContent = "Ask";
questionInput.value = "";
}
Your AI feature is fully coded. The serverless function knows how to call Claude, and your frontend JavaScript knows how to talk to that function. Next up, you'll deploy everything to Netlify and test it live on the internet.
Deploy to Netlify and Go Live
Your website is built, your serverless function is ready, and your JavaScript connects the two together. There's just one problem: it all lives on your computer.
In this step, you'll push your code to GitHub and deploy it to Netlify, a hosting platform that serves your site to anyone with a browser. Netlify also runs your serverless function securely, keeping your API key hidden from the public.
In this step, get ready to:
- Commit and push your code to GitHub.
- Sign up for Netlify and connect your repository.
- Test your live AI-powered website.
Commit and push your code to GitHub
Before Netlify can deploy your site, your latest code needs to be on GitHub. You wrote the serverless function and JavaScript in the previous step but haven't committed those changes yet.
- Open your terminal in Cursor by pressing Ctrl+` (backtick key, top left of your keyboard).
- Stage all your files for commit by running this command:
git add .
- Commit your changes with a descriptive message by running:
git commit -m "Add AI function and frontend logic"
What do these commands do?
- git add . stages every new and changed file in your project, telling Git "include these in the next snapshot."
- git commit -m "..." saves that snapshot with a message describing what changed. This creates a permanent record in your project's history.
- Push your commit to GitHub by running:
git push origin main
- You should see output mentioning your branch and a URL to your GitHub repository. This confirms your code is now live on GitHub.
Push rejected or authentication failed?
- If you see "Authentication failed", GitHub may need you to sign in. A browser window should open asking you to authorize Git. Follow the prompts and try the push again.
- If you see "Updates were rejected", run git pull origin main first, then try git push origin main again.
- Help me fix my git push error.
Sign up for Netlify and connect your repository
Netlify is a hosting platform that auto-deploys your site every time you push to GitHub. It also runs serverless functions, which is how your Claude API call stays secure.
- Open https://app.netlify.com in your browser.
- Click Sign up.
- Select GitHub as your sign-up method. This links your Netlify account to your GitHub account in one step.
- Authorize Netlify when GitHub asks for permission.
You should land on your Netlify team dashboard. Now connect your repository.
- Click Add new project on your team dashboard.
- Select Import an existing project.
- Choose GitHub as your Git provider.
- If prompted, install the Netlify GitHub App and grant it access to your ai-website repository (or all repositories).
- Select the ai-website repository from the list.
- Leave the build settings as-is. Netlify will auto-detect that no build command is needed for your static site.
- Click Deploy site.
Why Netlify instead of GitHub Pages?
GitHub Pages can only serve static files. Your project needs a serverless function to securely call the Claude API without exposing your API key in the browser.
Netlify runs your function in the cloud automatically. It detects the netlify/functions/ directory and handles everything.
Your site will deploy, but the AI feature won't work yet. The serverless function needs your API key, which you haven't told Netlify about.
- From your site's dashboard in Netlify, click Project configuration in the left sidebar.
- Click Environment variables.
- Click Add a variable, then select Add a single variable.
- In the Key field, enter ANTHROPIC_API_KEY.
- In the Values field, paste the API key you saved from platform.claude.com (it starts with sk-ant-).
- Click Create variable.
Why store the API key here?
Environment variables on Netlify are stored securely and never exposed in your code or to visitors. Your serverless function reads the key at runtime using Netlify.env.get("ANTHROPIC_API_KEY"), so the secret never appears in the browser.
- Now trigger a fresh deploy so Netlify picks up the new variable. In the left sidebar, click Deploys.
- Click Trigger deploy, then select Deploy site.
- Wait for the deploy status to show Published. This usually takes under a minute.
Deploy failed?
- Click on the failed deploy to view the deploy log. Look for error messages near the bottom.
- If you see "Function bundle error", check that your file is named exactly ask-claude.mjs (not .js) and lives in netlify/functions/.
- If the deploy log mentions missing files, make sure you committed all files with git add . and pushed to GitHub.
- Help me debug my Netlify deploy failure.
Test your live site
Your site is now live on the internet at a real URL that anyone can visit.
- Find your site URL at the top of your Netlify project dashboard. It looks something like https://random-name-123.netlify.app.
- Click the URL to open your live site in a new tab.
- Type a question in the input field, like What is HTML?.
- Click the Ask button.
- The button should change to "Thinking..." and then Claude's answer should appear in the response area above.
Getting an error instead of an answer?
- If you see "Error connecting to Claude", open your browser's developer tools (press F12), click the Console tab, and look for a red error message. It often reveals whether the function itself failed or the API returned an error.
- If the console shows a 401 or 403 error, your API key may be incorrect. Go back to Project configuration > Environment variables in Netlify, delete the variable, and re-add it with the correct key.
- If you see a 404 error, your function file might not be in the right location. Confirm the path is exactly netlify/functions/ask-claude.mjs in your repository.
- Help me debug why my Ask Claude feature isn't working on my live Netlify site.
Secret mission
Add Conversation Memory
Right now, every question you ask Claude is independent. Claude has no idea what you asked five seconds ago. In this mission, you'll build multi-turn conversation support so Claude remembers the full chat history within a session.
Clean Up Your Resources
Clean Up Your Resources
Decide whether to keep your resources running, pause them to come back later, or delete them entirely.
This project uses free tiers for all services. Your Anthropic account has approximately $5 in free API credits that will be consumed as visitors use your site's Ask Claude feature.
Cost warning
Your Netlify site is live and publicly accessible. Every time someone uses the Ask Claude feature, it consumes a small amount of your free Anthropic API credits.
At Claude Haiku 4.5 pricing ($1/MTok input, $5/MTok output), the $5 in free credits will last hundreds of requests. If credits run out, the AI feature will stop working but your site will stay online.
Resources you used:
- Git (installed on your computer).
- Cursor (installed on your computer).
- Node.js (installed on your computer).
- GitHub repository (ai-website).
- Anthropic API account and API key.
- Netlify account and deployed site.
- Local project files (index.html, style.css, script.js, netlify/functions/ask-claude.mjs).
Keep everything running
No action needed. Choose this if you want your site to stay live and the Ask Claude feature to keep working.
- Your Netlify site remains deployed and accessible at its URL.
- Your Anthropic API credits will be consumed as visitors use the AI feature.
- Your GitHub repository stays public with your commit history.
- Git, Cursor, and Node.js remain installed for future projects.
Pause - I'll come back to this later
Stop the AI feature from consuming credits while keeping your site and code intact.
- In Netlify, go to your site's Site configuration > Environment variables and delete the ANTHROPIC_API_KEY variable. This stops the AI feature without taking your site offline.
- Your site will still load, but the Ask Claude feature will return an error until you add the key back.
- Keep Git, Cursor, and Node.js installed for when you return.
- Your GitHub repository and local files stay as they are.
Delete - I don't want to use this again
Remove all project resources and accounts to start completely fresh.
- In Netlify, go to Site configuration > General > scroll to Delete site. Confirm the deletion.
- In GitHub, go to your ai-website repository > Settings > scroll to Delete this repository.
- In Anthropic's console, go to API Keys and delete the key you created for this project.
- Delete your local project folder (the ai-website folder on your Desktop).
- Git, Cursor, and Node.js are useful for future projects. Keep them unless you need the disk space.
That's a Wrap!
That's a Wrap!
Nice work. You just built an AI-powered website from scratch and shipped it to the internet using professional developer tools and workflows.
What you learned:
- Built and styled an interactive webpage using HTML, CSS, and JavaScript with help from Cursor's AI chat and inline editing features.
- Connected to the Claude API through a Netlify serverless function to securely power a working AI feature on your site.
- Used Git to version-control your code (clone, add, commit, push) and deployed to production via Netlify.
- Added conversation memory so Claude remembers previous messages in a session.
Ready to quiz yourself?