Cloud Watch: Demo

Build a live serverless demo with real-time CloudWatch observability.

Introduction

30 Second Summary

Every busy cafe has security cameras showing what's happening and a smoke detector that screams when something goes wrong. Cloud engineers use the exact same playbook to monitor their apps in production.

In this project, you will build an interactive observability demo powered by AWS Lambda, API Gateway, and CloudWatch. Your audience will tap a button on their phones, watch metrics spike on a live dashboard, and see an alarm fire when things break.

What You'll Build

Picture this: you project a live dashboard on screen, hand your audience a QR code, and watch the room light up as every tap on their phones sends real traffic through AWS infrastructure you built.

By the end of this project, you'll have:

  • A public API endpoint that anyone can hit from their phone to trigger real cloud infrastructure and generate live telemetry.
  • A real-time CloudWatch dashboard showing invocations, errors, and duration updating every 10 seconds as your audience generates traffic.
  • A CloudWatch Alarm that fires live when your audience generates enough errors, demonstrating automated alerting in action.
  • Secret Mission: Add a CloudWatch Logs Insights query widget to your dashboard for live error diagnosis during the demo.

Are there any prerequisites?

You need an AWS account with console access. If you are an IAM officer, your access should already be configured.

Before We Start

Before we dive into the AWS console, let's lock in what you're about to build and why it matters.

This project puts you in the shoes of a cloud engineer setting up a live observability demo. By the end, you'll have a system where your audience generates real traffic, watches metrics spike in real-time, and sees an alarm fire when things go wrong.

Create Your Lambda Function

Before anyone can trigger telemetry, you need the "barista" that handles incoming requests. This Lambda function is the thing that produces the metrics and logs your audience will watch.

Think of it like hiring a barista for your cafe who handles most orders perfectly but occasionally spills the coffee. That mix of successes and failures is what makes CloudWatch dashboards interesting during a live demo.

In this step, get ready to:
  • Create a Lambda function with the Python 3.13 runtime.
  • Deploy the cafe barista simulation code.
  • Test the function and confirm a mix of successes and failures.
Sign in and create your Lambda function
  • Open the AWS Lambda console by navigating to https://console.aws.amazon.com/lambda in your browser.
  • Choose Create function.
  • Select Author from scratch.
  • For Function name, enter cloud-watch-demo-cafe.
  • For Runtime, choose Python 3.13.
  • Leave Architecture set to the default (x86_64).
  • Under Permissions, leave the default (Create a new role with basic Lambda permissions).
  • Choose Create function.

After a few seconds, the console takes you to your new function's detail page. You should see the Code source pane with a default lambda_function.py file open in the editor.

What just happened?

Lambda created a function AND an IAM execution role for it automatically. The role gives your function permission to write logs to CloudWatch Logs.

Don't see the function page?

Make sure you chose Author from scratch (not a blueprint or container image). Double-check the function name has no spaces or special characters.

ask

Deploy the cafe barista code

The default code is just a placeholder. You need to replace it with a function that simulates a cafe barista who handles most orders fine but occasionally drops one.

  • In the Code source pane, click inside the lambda_function.py tab.
  • Select all the existing code and delete it.
  • Paste in the following cafe barista function:
import json
import random
import time

def lambda_handler(event, context):
    # Simulate processing time (like a barista making a drink)
    processing_time = random.uniform(0.1, 0.5)
    time.sleep(processing_time)

    # ~20% chance of failure (barista drops the order)
    if random.random() < 0.2:
        print("ERROR: Order dropped! The barista spilled the coffee.")
        raise Exception("Order failed: barista dropped the coffee!")

    # Success response (~80% of the time)
    order_id = random.randint(1000, 9999)
    print(f"SUCCESS: Order #{order_id} completed in {processing_time:.2f}s")

    return {
        "statusCode": 200,
        "headers": {
            "Content-Type": "application/json",
            "Access-Control-Allow-Origin": "*"
        },
        "body": json.dumps({
            "message": f"Order #{order_id} ready! Enjoy your cloud-brewed coffee.",
            "processing_time": f"{processing_time:.2f}s",
            "status": "success"
        })
    }

What does this code do?

  • random.uniform(0.1, 0.5) simulates a barista taking between 0.1 and 0.5 seconds to make a drink.
  • random.random() < 0.2 gives a ~20% chance of failure on each invocation. When this triggers, the function raises an exception, producing a real Lambda error.
  • The success path (~80%) returns a JSON response with a random order number. The Access-Control-Allow-Origin: * header allows browsers to call this function later from any domain.
  • Choose Deploy to save and deploy your function code.

You should see a confirmation banner at the top of the page indicating the function was updated.

✔️ Awesome, I've got everything!

Great. Make sure you clicked Deploy and saw the success confirmation before moving on.

ⓧ I'd like to double check the full code

Your lambda_function.py should match this exactly:

import json
import random
import time

def lambda_handler(event, context):
    # Simulate processing time (like a barista making a drink)
    processing_time = random.uniform(0.1, 0.5)
    time.sleep(processing_time)

    # ~20% chance of failure (barista drops the order)
    if random.random() < 0.2:
        print("ERROR: Order dropped! The barista spilled the coffee.")
        raise Exception("Order failed: barista dropped the coffee!")

    # Success response (~80% of the time)
    order_id = random.randint(1000, 9999)
    print(f"SUCCESS: Order #{order_id} completed in {processing_time:.2f}s")

    return {
        "statusCode": 200,
        "headers": {
            "Content-Type": "application/json",
            "Access-Control-Allow-Origin": "*"
        },
        "body": json.dumps({
            "message": f"Order #{order_id} ready! Enjoy your cloud-brewed coffee.",
            "processing_time": f"{processing_time:.2f}s",
            "status": "success"
        })
    }

Deploy button grayed out?

If Deploy is not clickable, make sure you changed the code in the editor. Lambda only enables the button when it detects unsaved changes.

help me deploy my Lambda function code

Test your function

Your barista is deployed, but you need to prove it works before giving it a front door. The Lambda console has a built-in test feature that invokes your function on demand.

  • Choose Test (near the top of the code editor).
  • In the Configure test event dialog, for Event name, enter demo-tap.
  • Leave the default JSON payload as-is (the function ignores the event body).
  • Choose Save.

Before you run the test, think about what you expect to happen. Will every invocation succeed, or will some fail?

  • Choose Test again to run the function.
  • Run it 5-6 times total by clicking Test repeatedly.

You should see a mix of results. Some executions succeed (green result showing your JSON response) and some fail (red result showing the error).

Why do some tests fail?

This is intentional. Your code has a ~20% failure rate built in. Those failures produce real Lambda error metrics that will make your CloudWatch dashboard light up during the live demo.

If every invocation succeeded, your dashboard would just show a flat line. The errors are what make observability interesting.

Seeing every test succeed or every test fail?

If all 5-6 tests produce the same result, keep clicking. With a 20% failure rate, you might get a streak of one outcome by chance. Try 10+ times and you should see both.

If EVERY test fails with an import error or syntax error, double-check your code matches the complete code exactly.

help me figure out why my Lambda function tests are all failing

Your barista is hired and already dropping orders on purpose. Next up, you will give this function a public front door so your audience can trigger it from their phones.

Wire Up the Front Door with API Gateway

Your Lambda function is live and producing a realistic mix of successes and failures. Right now, only you can trigger it using the Test button inside the AWS console.

Your audience needs a public URL they can hit from their phones. API Gateway is the "front door" that turns your private Lambda function into a public endpoint anyone on the internet can reach.

In this step, get ready to:
  • Create an HTTP API that connects to your Lambda function.
  • Test the public invoke URL in your browser.
  • Enable CORS so a trigger page can call your endpoint from any browser.
Create your HTTP API

An HTTP API is the simplest type of API in API Gateway. It gives your Lambda function a public URL with minimal configuration.

  • Open the API Gateway console at https://console.aws.amazon.com/apigateway.
  • Choose Create API.
  • Find the HTTP API card and choose Build.
  • Under Integrations, choose Add integration and select Lambda.
  • In the Lambda function field, enter cloud-watch-demo-cafe.
  • For API name, enter cloud-watch-demo-api.
  • Choose Next.
  • Review the route that API Gateway auto-creates (it matches your function name), then choose Next.
  • Review the stage ($default with auto-deploy enabled), then choose Next.
  • Choose Create.

What just happened?

You created an HTTP API with a Lambda integration. This means every request that hits your API's route gets forwarded directly to your cloud-watch-demo-cafe function.

The $default stage auto-deploys, so your API is immediately live. No separate deploy step needed.

Test the public invoke URL

Your API is now live on the internet. The API details page shows an Invoke URL at the top that anyone can use to reach your Lambda function.

  • On the API details page, find the Invoke URL displayed near the top of the page.
  • Copy the URL (it looks like https://{id}.execute-api.{region}.amazonaws.com).
  • Append your function route to it by adding /cloud-watch-demo-cafe to the end.
  • Paste the full URL into your browser's address bar and press Enter.

Before you look at the result, what do you expect to see? Think about what your Lambda function returns when it succeeds.

You should see a JSON response in your browser. Refresh the page several times. Sometimes you will see the success message with an order number, and sometimes you will get a 500 Internal Server Error.

Why am I seeing errors?

This is intentional. Your Lambda function raises an exception ~20% of the time, simulating a barista who occasionally drops an order. When the function raises an exception, API Gateway automatically returns a 500 error to the caller.

This mix of successes and failures is exactly what makes your CloudWatch dashboard interesting during a live demo.

Seeing "Not Found" instead of JSON?

Make sure you appended /cloud-watch-demo-cafe to the end of the invoke URL. The base URL alone does not have a route configured and returns a "Not Found" response.

Double-check there are no extra spaces or trailing slashes after the route name.

Help me troubleshoot my API Gateway invoke URL returning Not Found.

Enable CORS for cross-origin access

Later in this project, you will build an HTML trigger page that calls this endpoint using JavaScript. Browsers block cross-origin requests by default, so you need to enable CORS on your API.

  • In the API Gateway console, make sure your cloud-watch-demo-api is selected.
  • Choose CORS from the left navigation.
  • Choose Configure.
  • For Access-Control-Allow-Origin, enter * and choose Add.
  • For Access-Control-Allow-Methods, select * and choose Add.
  • Choose Save.

What is CORS?

CORS (Cross-Origin Resource Sharing) is a browser security feature. It blocks web pages from making requests to a different domain unless that domain explicitly allows it.

Setting the origin to * means "allow requests from anywhere." This is safe for a demo endpoint and necessary for the trigger page to work from any device.

  • Switch back to the browser tab where you tested your invoke URL and refresh the page.
  • Confirm you still see either a JSON success response or a 500 error.

Page not loading after CORS changes?

CORS settings apply to JavaScript-based requests from web pages. Direct browser navigation (typing the URL in the address bar) is not affected by CORS at all, so your URL should still work exactly as before.

If you are seeing unexpected behavior, confirm you saved the CORS configuration and that you are testing the correct URL with /cloud-watch-demo-cafe appended.

Help me troubleshoot my API Gateway CORS configuration.

Your API is now publicly accessible and ready for cross-origin requests. Anyone with the invoke URL can trigger your Lambda function from a browser, a phone, or a script.

Next up, you will build a CloudWatch dashboard that turns all this traffic into a visual story your audience can watch in real-time.

Build Your CloudWatch Dashboard

Your API is generating real metrics with every request it receives. Lambda automatically sends data about invocations, errors, and duration to CloudWatch in 1-minute intervals. But right now those metrics are scattered across AWS like security footage no one is watching.

In this step, you will build a CloudWatch dashboard that tells a visual story. Think of it as the security camera system for your cafe. Instead of digging through raw metric namespaces, your audience sees a single screen showing everything that is happening in real-time.

In this step, get ready to:
  • Create a CloudWatch dashboard with Invocations and Errors line graphs.
  • Add a Duration widget and a live hit counter.
  • Configure auto-refresh and time range for live demo mode.
Create your dashboard and add the first widget

CloudWatch dashboards let you arrange metric visualizations on a single screen. You will create one and add the first widget showing how often your function gets called and how often it fails.

  • Open the CloudWatch console.
  • In the left navigation, choose Dashboards.
  • Choose Create dashboard.
  • For the dashboard name, enter CloudWatch-Demo-Day.
  • Choose Create dashboard.

A widget type picker appears. This is where you choose how to visualize your first metric.

  • Select Line as the widget type.
  • Choose Next.
  • Select Metrics as the data source.
  • In the Browse tab, select Lambda.
  • Select By Function Name.
  • Find cloud-watch-demo-cafe and check both Invocations and Errors.
  • Choose Create widget.

Your first widget appears on the dashboard. It shows a line graph tracking how many times your function is invoked and how many of those invocations fail.

What does this widget show?

The Invocations line counts every time your Lambda function runs. The Errors line counts executions that raised an exception (your barista dropping the coffee ~20% of the time).

During the live demo, the gap between these two lines is the visual story: most requests succeed, but a steady stream of errors tells the audience something is wrong.

Add the Duration and live counter widgets

Two more widgets complete the story. A Duration graph shows how long each request takes. A Number widget gives the audience a big, satisfying counter of total hits.

  • Choose Add widget.
  • Select Line as the widget type.
  • Choose Next.
  • Select Metrics as the data source.
  • In the Browse tab, select Lambda, then By Function Name.
  • Find cloud-watch-demo-cafe and check Duration.
  • Choose Create widget.

A second line graph appears, showing how long each request takes to process. Now add the live counter.

  • Choose Add widget.
  • Select Number as the widget type.
  • In the Browse tab, select Lambda, then By Function Name.
  • Find cloud-watch-demo-cafe and check Invocations.

Before you create this widget, you need to configure it to show a running total instead of an average.

  • In the Graphed metrics tab, select the dropdown under Statistic and choose Sum.
  • Select the dropdown under the Period column and choose 1 Minute.
  • Choose Create widget.
  • Choose Save at the top of the dashboard.

Your dashboard now has three widgets. The Number widget displays a big counter that shows total invocations per minute. During the live demo, this gives your audience a satisfying number that ticks up with each tap.

Why Sum instead of Average?

The default statistic is Average, which would show "1" for every minute (one invocation averaged over the period). Sum shows the total count of invocations in each minute. That is what makes the counter useful as a live hit tracker during your demo.

Don't see Lambda metrics in the Browse tab?

Lambda metrics only appear in CloudWatch after the function has been invoked at least once. If you do not see Lambda listed, go back to the Lambda console and run the test event a few more times. Wait 1-2 minutes, then try adding the widget again.

Also confirm you are in the same AWS region where you created your Lambda function. The region selector is in the top-right corner of the console.

Still stuck? Help me find my Lambda metrics in the CloudWatch Browse tab.

Configure your dashboard for live demo mode

By default, the dashboard refreshes every few minutes and shows a wide time range. For a live demo, you want frequent updates and a tight window so the audience sees activity, not empty space.

  • At the top-right corner of your dashboard, open the Refresh options menu.
  • Choose 10 Seconds.
  • Next to the refresh menu, open the time range selector.
  • Set it to Last 15 minutes.

What does Live Data mode do?

With a 10-second refresh interval, CloudWatch pulls the most recent data point as soon as any data is published in the corresponding aggregation interval. This means your audience sees near-real-time updates during the demo instead of waiting several minutes for the dashboard to catch up.

Before you test the dashboard, what do you think you will see if you trigger your API 10-15 times and then check the graphs?

  • Open your API Gateway invoke URL in a new browser tab (the URL from Step 2).
  • Refresh that page 10-15 times to generate traffic.
  • Wait 1-2 minutes for CloudWatch to aggregate the data.
  • Return to your CloudWatch dashboard and confirm it refreshes.

You should see the Invocations and Errors lines spike upward on your first widget. The Duration graph shows processing times. The Number widget displays the total count of invocations in the most recent minute.

Dashboard still showing empty graphs?

CloudWatch metrics from Lambda have a 1-minute aggregation interval. If you just triggered the requests, wait a full 2 minutes before refreshing. The data will appear.

If the time range is set to a wider window (like 3 hours), the data points may be too small to see. Confirm you set the range to Last 15 minutes.

Need more help? My CloudWatch dashboard is not showing any data after triggering my API.

Your security cameras are rolling. You have a live dashboard that updates every 10 seconds and tells a clear visual story. Next up, you will share this dashboard publicly and build a trigger page so your audience can generate the traffic themselves.

Go Live: Share Dashboard and Build Trigger Page

Your dashboard looks great to you, but your audience cannot see it. They do not have AWS accounts.

CloudWatch lets you share dashboards publicly via a link that requires zero credentials to view. Combined with a simple HTML trigger page, your audience gets two things: a button to tap (generating live traffic) and a dashboard to watch (seeing that traffic in real-time). This is the "show, not tell" moment that turns your demo from a slideshow into a live experience.

In this step, get ready to:
  • Share your CloudWatch dashboard publicly so anyone with the link can view it.
  • Build an HTML trigger page that lets audience members fire requests from their phones.
  • Plan your live demo setup with two audience-facing links.
Share the dashboard publicly

Right now your CloudWatch-Demo-Day dashboard is only visible to someone logged into your AWS account. You need a public link that works for anyone.

  • Return to the CloudWatch console in your browser.
  • In the left navigation, choose Dashboards.
  • Choose the name of your dashboard (CloudWatch-Demo-Day).
  • Choose Actions, then Share dashboard.
  • Next to "Share your dashboard publicly," choose Start sharing.
  • Type Confirm in the text box.
  • Read the agreement and select the confirmation checkbox, then choose Preview policy.
  • Review the resources that will be shared, then choose Confirm and generate shareable link.
  • On the next page, choose Copy link to clipboard.
  • Save this link somewhere safe (a notes app, a document, or pinned in a browser tab). This is your audience-facing dashboard URL.

What does sharing publicly mean?

When you share publicly, CloudWatch creates an IAM role that grants viewers read-only access to your dashboard metrics. Anyone with the link can see your Invocations, Errors, and Duration graphs without needing an AWS account.

This is safe for a demo account with non-sensitive data. AWS documents the warning: "Do this only for dashboards that do not contain sensitive information."

Verify the public link works by opening it in an incognito or private browser window (where you are not logged into AWS). You should see your dashboard with all three metric widgets visible.

Dashboard link shows an error or blank page?

  • Make sure you completed the full sharing flow, including typing Confirm and choosing Confirm and generate shareable link. If you closed the dialog early, try the sharing steps again.
  • Wait 30 seconds and refresh. The sharing role takes a moment to propagate.
  • If your IAM user does not have permission to create roles, ask your account administrator to grant the iam:CreateRole and iam:CreatePolicy permissions.

Still stuck? Help me troubleshoot why my CloudWatch public dashboard link is not working.

Create the HTML trigger page

Your audience needs a way to fire requests at your API from their phones. You will build a simple HTML page with a big button that calls your API Gateway endpoint and displays live counters of total requests, successes, and errors.

  • Open any text editor on your computer (Notepad, TextEdit, VS Code, or any editor you prefer).
  • Create a new file and save it as trigger.html on your Desktop.
  • Paste the following code into the file. This is the <head> section containing the page title and all the styling:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Cloud Watch Demo Day - Trigger</title>
    <style>
        * { margin: 0; padding: 0; box-sizing: border-box; }
        body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%); color: #fff; min-height: 100vh; display: flex; flex-direction: column; align-items: center; justify-content: center; padding: 20px; }
        h1 { font-size: 2rem; margin-bottom: 10px; text-align: center; }
        .tagline { font-size: 1rem; color: #a0a0a0; margin-bottom: 40px; text-align: center; }
        .trigger-btn { width: 200px; height: 200px; border-radius: 50%; border: none; background: linear-gradient(145deg, #e94560, #c23152); color: #fff; font-size: 1.2rem; font-weight: bold; cursor: pointer; box-shadow: 0 10px 30px rgba(233, 69, 96, 0.4); transition: transform 0.1s, box-shadow 0.1s; margin-bottom: 30px; }
        .trigger-btn:active { transform: scale(0.95); box-shadow: 0 5px 15px rgba(233, 69, 96, 0.3); }
        .stats { display: flex; gap: 30px; margin-bottom: 30px; }
        .stat-box { text-align: center; }
        .stat-number { font-size: 2.5rem; font-weight: bold; }
        .stat-label { font-size: 0.8rem; color: #a0a0a0; text-transform: uppercase; }
        .success { color: #4ecdc4; }
        .errors { color: #e94560; }
        .total { color: #f9d56e; }
        .response { background: rgba(255,255,255,0.05); border-radius: 10px; padding: 15px 25px; max-width: 400px; width: 100%; text-align: center; min-height: 60px; display: flex; align-items: center; justify-content: center; font-size: 0.9rem; color: #ccc; }
    </style>
</head>

What does this code do?

  • The CSS creates a dark-themed page with a large round red button, stat counters for Total/Success/Errors, and a response display area.
  • The .trigger-btn:active style makes the button shrink slightly on tap, giving mobile users satisfying feedback.
  • Each counter (.success, .errors, .total) has a distinct color so the audience can instantly see the split.
  • Directly below the </head> tag, paste the body HTML that creates the button, stat counters, and response display:
<body>
    <h1>Cloud Watch: Demo Day</h1>
    <p class="tagline">Tap the button. Trigger live AWS telemetry.</p>

    <button class="trigger-btn" onclick="triggerRequest()">
        TRIGGER<br>REQUEST
    </button>

    <div class="stats">
        <div class="stat-box">
            <div class="stat-number total" id="total-count">0</div>
            <div class="stat-label">Total</div>
        </div>
        <div class="stat-box">
            <div class="stat-number success" id="success-count">0</div>
            <div class="stat-label">Success</div>
        </div>
        <div class="stat-box">
            <div class="stat-number errors" id="error-count">0</div>
            <div class="stat-label">Errors</div>
        </div>
    </div>

    <div class="response" id="response-box">
        Tap the button to send your first request!
    </div>

What does this code do?

  • The <button> element calls triggerRequest() every time it is tapped. This is the main interaction point for your audience.
  • Three counter elements (total-count, success-count, error-count) display how many requests have been sent and their outcomes.
  • The response-box shows the latest response message from your Lambda function.
  • Finally, paste the JavaScript that powers the button. Add this directly below the response-box div:
    <script>
        const API_URL = "[[INVOKE_URL="your API Gateway invoke URL followed by /cloud-watch-demo-cafe"]]";

        let totalCount = 0;
        let successCount = 0;
        let errorCount = 0;

        async function triggerRequest() {
            totalCount++;
            document.getElementById("total-count").textContent = totalCount;
            document.getElementById("response-box").textContent = "Sending request...";

            try {
                const response = await fetch(API_URL);
                if (response.ok) {
                    const data = await response.json();
                    successCount++;
                    document.getElementById("success-count").textContent = successCount;
                    document.getElementById("response-box").textContent = data.message;
                } else {
                    errorCount++;
                    document.getElementById("error-count").textContent = errorCount;
                    document.getElementById("response-box").textContent = "500 - Order dropped! The barista spilled the coffee.";
                }
            } catch (err) {
                errorCount++;
                document.getElementById("error-count").textContent = errorCount;
                document.getElementById("response-box").textContent = "Network error: " + err.message;
            }
        }
    </script>
</body>
</html>

What does this code do?

  • The API_URL constant holds your API Gateway endpoint. Every button tap sends a fetch() request to this URL.
  • On success (response.ok), it increments the success counter and displays the order message from Lambda.
  • On failure (500 error or network error), it increments the error counter and shows the error message.
  • The counters update instantly on every click, giving your audience real-time feedback before the dashboard even updates.
  • Replace the API_URL placeholder value with your actual API Gateway invoke URL from Step 2. It should look like https://{id}.execute-api.{region}.amazonaws.com/cloud-watch-demo-cafe with your real ID and region.
  • Save trigger.html.
  • Open trigger.html in your browser by double-clicking the file on your Desktop.
  • Click the big red TRIGGER REQUEST button several times.

You should see the Total counter climb with each click. Some clicks will show a success message with an order number. Others will show "500 - Order dropped!" This is your Lambda's intentional 20% error rate in action.

Button clicks do nothing or show network errors?

  • Check that you replaced the placeholder URL with your real invoke URL. The URL must end with /cloud-watch-demo-cafe.
  • Make sure CORS is enabled on your API Gateway (configured in Step 2). Without it, the browser blocks the request.
  • Open your browser's Developer Tools (F12) and check the Console tab for error messages. A CORS error looks like "blocked by CORS policy."

Still stuck? Help me debug why my trigger.html page cannot reach my API Gateway endpoint.

✔️ Awesome, I've got everything!

Great. Double check you have saved trigger.html and confirmed the button produces both success and error responses.

ⓧ I'd like to double check the full code

Your trigger.html file should contain these three sections in order:

  • The <head> section with the <style> block (all the CSS rules from the first chunk above).
  • The <body> HTML with the heading, tagline, button, stats divs, and response box.
  • The <script> block with API_URL, the three counter variables, and the triggerRequest() async function.

Scroll up and confirm each section is present in your file. Make sure API_URL contains your real invoke URL (not the placeholder).

Plan your live demo setup

For your live demo, you need two things visible to your audience: the public dashboard on the main screen and the trigger page on their phones.

  • Project the public CloudWatch dashboard link on your main screen or monitor. Open it in a browser and fullscreen it.
  • For the trigger page, you have options: share the trigger.html file directly, upload it to an S3 bucket configured for static website hosting, or host it on any web server.
  • Generate a QR code for the trigger page URL using any free QR code generator. This lets audience members scan and open the page on their phones instantly.

Keep both links handy

Write down or bookmark two links: (1) the public dashboard URL for your projected screen, and (2) the trigger page URL or QR code for your audience. Having these ready means zero fumbling when it is demo time.

Now verify the full end-to-end flow. Before you do, predict: if you click the trigger button 10 times and then check the public dashboard, what do you expect to see on the Invocations graph?

  • Open your public dashboard link in an incognito or private browser window (confirming you are not logged into AWS).
  • In a separate tab, open trigger.html and click the button 10-15 times.
  • Wait 1-2 minutes (CloudWatch metrics have a 1-minute aggregation interval).
  • Refresh the public dashboard in your incognito window.

You should see the Invocations and Errors graphs start to show data points spiking up. The Number widget should display a count matching your clicks. This is exactly what your audience will see during the live demo.

Dashboard not updating after clicking?

  • CloudWatch metrics take 1-2 minutes to appear. Wait and refresh again.
  • Make sure the dashboard time range is set to Last 15 minutes (not a longer range where your few clicks would be invisible).
  • Confirm your trigger page is actually reaching the API by checking that the success/error counters increment when you click.

Still stuck? Help me figure out why my CloudWatch dashboard is not showing data from my trigger page clicks.

Your demo is live. Audience members can tap a button on their phones and watch real AWS infrastructure respond in real-time on the big screen. Next up, you will add a CloudWatch Alarm that fires when the audience generates too many errors, adding drama to the demo.

Set Up the CloudWatch Alarm

Your dashboard is live and your audience can watch metrics spike in real time. But dashboards only show what is happening. They do not tell you when something goes wrong.

A CloudWatch Alarm adds automated alerting to your demo. When the audience generates enough errors, the alarm fires on its own. Think of it like a smoke detector going off in the cafe because the barista keeps burning orders.

In this step, get ready to:
  • Create a CloudWatch Alarm that monitors the Lambda Errors metric.
  • Configure a low threshold so the alarm fires during your live demo.
  • Test the alarm by clicking the trigger page rapidly and watching it transition to "In alarm" state.
Select the Errors metric for your alarm

Your alarm needs to know which metric to watch. You will point it at the Errors metric for your cloud-watch-demo-cafe Lambda function.

  • In the CloudWatch console, choose Alarms from the left navigation.
  • Choose All alarms.
  • Choose Create alarm.
  • Choose Select metric.
  • Under Browse, select Lambda.
  • Select By Function Name.
  • Find cloud-watch-demo-cafe and check the box next to the Errors metric.
  • Choose Select metric.

What is this metric tracking?

The Errors metric counts how many times your Lambda function throws an unhandled exception. Every time the barista "drops an order" (your function raises an exception), this metric increments by 1.

Lambda automatically sends this metric to CloudWatch every minute, with no extra setup required.

Configure the alarm threshold

Now you will set the conditions that make the alarm fire. A low threshold ensures the alarm triggers during your demo when the audience is clicking away.

  • Set Statistic to Sum.
  • Set Period to 1 minute.
  • Under Conditions, for the threshold type select Static.
  • For "Whenever Errors is", select Greater and enter 3 as the threshold value.
  • Choose Next.

Why set the threshold so low?

A threshold of 3 means the alarm fires if more than 3 errors happen in a single minute. Since your function fails about 20% of the time, just 20 audience clicks should produce around 4 errors. That crosses the threshold and triggers the alarm live during your presentation.

  • Under Notification, choose Remove to skip email notifications for this demo.
  • Choose Next.
  • For Alarm name, enter CafeErrorAlarm-DemoDay.
  • Choose Next.
  • Under Preview and create, confirm your settings and choose Create alarm.

Your alarm now appears in the Alarms list with an OK state. That means it is watching but has not triggered yet.

Don't see your alarm listed?

  • Make sure you are viewing All alarms in the left navigation, not a filtered view.
  • Confirm you completed the final step by clicking Create alarm on the review page.
  • Check that you selected the Errors metric (not Invocations or Duration) in the first step.

Help me troubleshoot my CloudWatch Alarm creation.

Test the alarm with rapid clicks

Time to prove the smoke detector works. You will generate a burst of traffic that crosses your error threshold.

  • Switch to the browser tab with your trigger.html page.
  • Click the TRIGGER REQUEST button rapidly 20 or more times.

Watch the error counter on the page. You should see roughly 4 or more errors accumulate out of 20 clicks.

Before you check the alarm, what do you think its state is now? Did 20 clicks generate enough errors to cross a threshold of 3 in a single minute?

  • Wait 1-2 minutes for CloudWatch to process the metrics.
  • Return to the CloudWatch console.
  • Choose Alarms from the left navigation, then All alarms.

Your CafeErrorAlarm-DemoDay alarm should now show In alarm state (highlighted in red). The smoke detector went off because the audience broke the cafe.

What just happened?

Your 20+ clicks produced around 4 errors within one minute. That crossed the threshold of 3 you configured. CloudWatch evaluated the Errors Sum for that 1-minute period, saw it exceeded 3, and transitioned the alarm from OK to In alarm.

During your live demo, this is the dramatic moment. You say: "The audience just broke the cafe. CloudWatch caught it."

Alarm still showing OK?

  • CloudWatch metrics have a 1-2 minute delay. Wait a full 2 minutes and refresh the Alarms page.
  • Make sure you clicked rapidly enough to send 20+ requests within a short window. If requests were spread over several minutes, errors may not exceed 3 in any single 1-minute period.
  • Double-check that the trigger page is using your actual API Gateway URL, not the placeholder URL. If requests are failing with network errors, they do not reach Lambda and do not generate the Errors metric.

Help me figure out why my CloudWatch Alarm is not transitioning to In alarm state.

Secret mission

Add Live Error Diagnosis with Logs Insights

Your audience saw the alarm fire, but a real cloud engineer asks "why did it break?" In this mission, you will add a Logs Insights query widget to your dashboard that shows live error messages. This completes the observability story from detection to diagnosis.

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 runs entirely within the AWS Free Tier, so there are no ongoing costs for normal demo usage.

Resources you used:

  • Lambda function (cloud-watch-demo-cafe).
  • HTTP API in API Gateway (cloud-watch-demo-api).
  • CloudWatch Dashboard (CloudWatch-Demo-Day) with public sharing enabled.
  • CloudWatch Alarm (CafeErrorAlarm-DemoDay).
  • Local file trigger.html on your computer.

Keep everything running

No action needed. Choose this if you plan to use this for a demo or presentation soon.

  • The Free Tier covers 1M Lambda requests/month, 1M API Gateway HTTP API calls/month, 3 CloudWatch dashboards, and 10 CloudWatch alarms.
  • Your public dashboard link stays active. Anyone with the link can view your metrics without AWS credentials.
  • Your trigger.html file remains on your computer and continues pointing to your live API endpoint.

Pause - I'll come back to this later

Disable public access to your dashboard while keeping all resources intact. This way you can re-enable sharing when you are ready to present.

  • Open the CloudWatch console.
  • In the left navigation, choose Dashboards.
  • Choose the name of your CloudWatch-Demo-Day dashboard.
  • Choose Actions, then Share dashboard.
  • Choose Stop sharing.
  • In the confirmation box, choose Stop sharing again to confirm.

Your Lambda function, API Gateway endpoint, dashboard, and alarm all remain intact. Only the public link is deactivated.

Delete - I don't want to use this again

Remove all project resources and start fresh. Follow each step below to fully clean up.

Delete the Lambda function:

  • Open the Functions page of the Lambda console.
  • Select cloud-watch-demo-cafe.
  • Choose Actions, Delete.
  • Type confirm in the text input field and choose Delete.

Delete the HTTP API:

  • Open the APIs page of the API Gateway console.
  • Select cloud-watch-demo-api.
  • Choose Actions, then choose Delete.
  • Choose Delete to confirm.

Delete the CloudWatch Alarm:

  • Open the CloudWatch console and choose Alarms in the left navigation.
  • Select CafeErrorAlarm-DemoDay.
  • Choose Actions, then choose Delete.
  • Confirm the deletion.

Delete the CloudWatch Dashboard:

  • In the CloudWatch console, choose Dashboards in the left navigation.
  • Select CloudWatch-Demo-Day.
  • Choose Delete.
  • Confirm the deletion.

Disable dashboard sharing to remove the public access role:

  • In the CloudWatch console, choose Settings in the left navigation.
  • In the Dashboard sharing section, choose Stop sharing all dashboards.
  • In the confirmation box, choose Stop sharing all dashboards to confirm.

Delete the local trigger page:

  • Delete the trigger.html file from your computer. You can drag it to the Trash (macOS) or Recycle Bin (Windows).

That's a Wrap!

That's a Wrap!

Nice work! You just built a fully interactive observability demo where your audience generates real cloud traffic and watches the telemetry unfold live.

You've learned how to:

  • Deploy a Lambda function that simulates realistic production behavior and wire it to a public API Gateway endpoint anyone on the internet can trigger.
  • Build a real-time CloudWatch dashboard with metrics widgets showing Invocations, Errors, and Duration, then share it publicly so audience members can view live telemetry without AWS accounts.
  • Create a CloudWatch Alarm that fires when error rates cross a threshold, demonstrating automated alerting to your audience in real time.
  • Secret Mission: Added a Logs Insights query widget for live error diagnosis, completing the observability story from "something is wrong" to "here is exactly what is wrong."

Ready to quiz yourself?