HTML5 Web APIs — Geolocation, Drag & Drop, Web Storage, Web Workers, and Server-Sent Events
Lesson 34 — HTML5 Web APIs: Supercharging Your Web Pages
Lesson Introduction
You already know how to build web pages with HTML, style them with CSS, and add interaction with JavaScript. But did you know that browsers come with a set of built-in superpowers you can tap into — completely for free?
These superpowers are called Web APIs. In this lesson, you will learn what a Web API is, and then master five of the most important ones: Geolocation, Drag and Drop, Web Storage, Web Workers, and Server-Sent Events.
By the end of this lesson, you will be able to:
- Explain what a Web API is and why it matters
- Build a page that detects a user’s location
- Create draggable elements that can be dropped into target zones
- Store data in the browser so it survives page refreshes
- Run background tasks without freezing the page
- Receive live updates from a server without reloading the page
Prerequisite Concepts
Before diving in, let us quickly cover the ideas you need to understand this lesson.
What is JavaScript?
JavaScript is the programming language of the web. It lets you make web pages respond to user actions — clicking a button, typing in a form, hovering over an image. If you have written a little JavaScript before (like document.getElementById() or alert()), you are ready for this lesson.
What is an Event?
An event is something that happens in the browser — a click, a keypress, a page load, a timer firing. In JavaScript, you can “listen” for these events and run code when they happen.
What is a Function?
A function is a named block of code you can run whenever you need it:
function sayHello() {
alert("Hello!");
}
// Call it like this:
sayHello();
Output: An alert box saying “Hello!”
What is an Object?
An object is a container that holds related data and actions. For example, navigator.geolocation is an object — it holds everything you need to work with location data.
Part 1 — What is a Web API?
1.1 The Big Idea
Let us start with a simple real-world analogy.
Imagine you work at a restaurant. You don’t need to know how the kitchen prepares every dish — you just pick up the phone (the interface), say what you want, and the kitchen takes care of the rest.
A Web API (Application Programming Interface) works exactly the same way. It is a ready-made set of tools built into the browser that allows your JavaScript code to ask the browser to do complex things — like find the user’s location, store data, or draw graphics — without you having to build that complex machinery yourself.
API stands for Application Programming Interface. Think of it as a “remote control” for features built into the browser or operating system.
1.2 HTML5 Built-in APIs
All modern browsers come with a collection of built-in Web APIs. Here are the main HTML5 APIs:
| API | What It Does |
|---|---|
| Geolocation API | Finds the user’s current GPS location (latitude and longitude) |
| Drag and Drop API | Lets users grab elements and drag them to new positions |
| Web Storage API | Stores key/value data in the browser (better than cookies) |
| Web Workers API | Runs JavaScript in the background without freezing the page |
| Server-Sent Events API | Lets the server push live updates to the web page automatically |
1.3 Third-Party APIs
Beyond built-in APIs, there are also third-party APIs — services provided by other companies. Examples include the YouTube API (embed videos), the Twitter API (display tweets), and the Facebook API (show social data). You would download code from those services to use them. This lesson focuses entirely on built-in browser APIs.
1.4 Three Golden Rules When Using Any API
Before you write a single line of code using any Web API, always follow these three rules:
Rule 1 — Check Browser Capability: Not every browser supports every API. Always check whether the browser supports it before trying to use it.
Rule 2 — Add Error Handling: APIs can fail (user denies permission, network error, etc.). Always have a plan for when things go wrong.
Rule 3 — Request User Permission: Some APIs access sensitive data (like location). You must always ask the user for permission first. Never access private data silently.
Part 2 — The HTML5 Geolocation API
2.1 What is Geolocation?
Geolocation means “finding where something is on Earth.” The Geolocation API lets your web page ask the browser: “Where is this device right now?”
The browser will then use one or more of these methods to figure out the location:
- GPS (most accurate, used on phones and watches)
- Wi-Fi triangulation (uses nearby Wi-Fi networks)
- Cell tower triangulation (uses mobile network signals)
- IP address lookup (least accurate, used on desktops)
Important: The Geolocation API only works on HTTPS (secure) connections, not on plain HTTP. This is a browser security requirement to protect user privacy.
2.2 How It Works — The Simple Version
Think of it like calling a taxi dispatcher:
- You call the dispatcher (
navigator.geolocation) and say “send me my position” - The dispatcher checks with the driver and sends back coordinates
- If the driver is unavailable (error), you get an error message instead
2.3 Accessing the Geolocation API
The Geolocation API lives inside the navigator object in JavaScript. navigator is a built-in browser object that holds information about the browser itself.
navigator.geolocation
If the browser supports Geolocation, this will be an object with methods. If not, it will be undefined.
2.4 Step 1 — Check Browser Support
Before using Geolocation, always check if it is supported:
if (navigator.geolocation) {
console.log("Geolocation is supported!");
} else {
console.log("Geolocation is NOT supported in this browser.");
}
Output (if supported): Geolocation is supported!
2.5 Step 2 — Get the Current Position
The main method is getCurrentPosition(). It takes two arguments:
- A success function — runs when location is found
- An error function — runs when something goes wrong
navigator.geolocation.getCurrentPosition(successFunction, errorFunction);
2.6 A Complete Geolocation Example
Let us put it all together:
<!DOCTYPE html>
<html>
<body>
<p id="demo">Click the button to get your location.</p>
<button onclick="getLocation()">Get My Location</button>
<script>
const display = document.getElementById("demo");
function getLocation() {
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(success, error);
} else {
display.innerHTML = "Geolocation is not supported by this browser.";
}
}
function success(position) {
display.innerHTML =
"Latitude: " + position.coords.latitude +
"<br>Longitude: " + position.coords.longitude;
}
function error() {
display.innerHTML = "Sorry, unable to retrieve your location.";
}
</script>
</body>
</html>
Expected Output (if user allows and has GPS):
Latitude: 6.5244
Longitude: 3.3792
(The numbers will match your actual location.)
2.7 Line-by-Line Explanation
const display = document.getElementById("demo");
This finds the paragraph element with id="demo" and stores it in the display variable so we can update it later.
function getLocation() {
We define a function called getLocation that runs when the user clicks the button.
if (navigator.geolocation) {
This checks whether the geolocation object exists inside navigator. If it does, the browser supports Geolocation.
navigator.geolocation.getCurrentPosition(success, error);
This calls getCurrentPosition(). The browser will ask the user for permission to access their location. If they allow it, success is called. If anything goes wrong, error is called.
function success(position) {
display.innerHTML =
"Latitude: " + position.coords.latitude +
"<br>Longitude: " + position.coords.longitude;
}
The success function receives a position object automatically. This object has a coords property which contains latitude, longitude, accuracy, and more. We display the two most important ones.
2.8 What Data Does getCurrentPosition() Return?
The position object contains these properties:
| Property | Description | Always Returned? |
|---|---|---|
coords.latitude |
The latitude (north-south position) as a decimal | ✅ Yes |
coords.longitude |
The longitude (east-west position) as a decimal | ✅ Yes |
coords.accuracy |
How accurate the position is, in meters | ✅ Yes |
coords.altitude |
Height above sea level in metres | ⚠️ If available |
coords.altitudeAccuracy |
Accuracy of the altitude value | ⚠️ If available |
coords.heading |
Direction of travel in degrees (0 = North) | ⚠️ If available |
coords.speed |
Speed of travel in metres per second | ⚠️ If available |
timestamp |
When the position was determined | ⚠️ If available |
2.9 Better Error Handling
The error function can receive an error object that tells you why it failed. There are four possible error codes:
function error(err) {
switch(err.code) {
case err.PERMISSION_DENIED:
display.innerHTML = "User denied permission to access location.";
break;
case err.POSITION_UNAVAILABLE:
display.innerHTML = "Location information is unavailable.";
break;
case err.TIMEOUT:
display.innerHTML = "The request to get location timed out.";
break;
case err.UNKNOWN_ERROR:
display.innerHTML = "An unknown error occurred.";
break;
}
}
Thinking Prompt: What happens if the user is indoors with no GPS signal and weak Wi-Fi? Which error case might fire?
2.10 Watching the User Move — watchPosition()
If you want to keep tracking the user’s position as they move (like a navigation app), use watchPosition() instead of getCurrentPosition(). It works the same way but keeps firing the success function every time the position changes.
// Start watching
let watchID = navigator.geolocation.watchPosition(success, error);
// To stop watching:
navigator.geolocation.clearWatch(watchID);
The watchID is a number that identifies this specific watch. You pass it to clearWatch() when you want to stop.
2.11 Real-World Uses of Geolocation
- Delivery apps (show rider’s live position on a map)
- Restaurant finders (“restaurants near me”)
- Weather apps (get weather for the user’s city automatically)
- Turn-by-turn navigation (Google Maps, Waze)
- Fitness trackers (map your running route)
Part 3 — The HTML5 Drag and Drop API
3.1 What is Drag and Drop?
You already use drag and drop every day. When you move a file from your Downloads folder to your Desktop, you are dragging and dropping. When you rearrange apps on your phone’s home screen — that is drag and drop too.
The HTML5 Drag and Drop API lets you build the same behaviour directly in web pages. Users can click (or touch) an element, hold it, drag it across the screen, and release it somewhere else.
3.2 The Three Key Players
Every drag and drop interaction involves three things:
- The draggable element — the thing you pick up and move
- The drop zone — the area where you can release it
- JavaScript event handlers — the code that runs during each stage
3.3 The Drag and Drop Events
| Event | When It Fires | Attached To |
|---|---|---|
ondragstart |
When the user starts dragging an element | The draggable element |
ondragover |
When a dragged element is moved over a drop target | The drop zone |
ondrop |
When the dragged element is released over a drop target | The drop zone |
3.4 Step 1 — Make an Element Draggable
To make any HTML element draggable, add the draggable="true" attribute:
<img id="myImage" src="logo.gif" draggable="true">
or for a paragraph:
<p id="myText" draggable="true">Drag me!</p>
By default, HTML elements are not draggable. You must explicitly set draggable="true".
3.5 Step 2 — The ondragstart Handler
When dragging starts, you need to tell the browser what data to carry with the dragged element. You do this using dataTransfer.setData():
function dragstartHandler(event) {
// Store the id of the element being dragged
event.dataTransfer.setData("text", event.target.id);
}
Breaking this down:
event— the drag event object, automatically passed inevent.dataTransfer— a special object for passing data between the drag source and the drop targetsetData("text", value)— stores a piece of data with the key “text” and the value of the element’sidevent.target.id— theidattribute of the element being dragged
3.6 Step 3 — Allow Dropping with ondragover
By default, browsers do not allow dropping elements onto other elements. To allow it, you must prevent the default behaviour in ondragover:
function dragoverHandler(event) {
event.preventDefault(); // This is what allows the drop!
}
Without event.preventDefault() here, the ondrop event will never fire.
3.7 Step 4 — Handle the Drop with ondrop
When the user releases the dragged element over a valid drop target, ondrop fires. Here you grab the data and move the element:
function dropHandler(event) {
event.preventDefault(); // Prevent browser default (opening as link)
// Retrieve the id we stored during dragstart
const draggedId = event.dataTransfer.getData("text");
// Move the dragged element into the drop zone
event.target.appendChild(document.getElementById(draggedId));
}
Breaking this down:
event.dataTransfer.getData("text")— retrieves the id we stored duringdragstartdocument.getElementById(draggedId)— finds the dragged element in the DOMevent.target.appendChild(...)— moves that element inside the drop zone
3.8 A Complete Drag and Drop Example
<!DOCTYPE HTML>
<html>
<head>
<style>
#dropZone {
width: 200px;
height: 100px;
border: 3px dashed #555;
background-color: #f9f9f9;
padding: 10px;
}
</style>
<script>
function dragstartHandler(ev) {
ev.dataTransfer.setData("text", ev.target.id);
}
function dragoverHandler(ev) {
ev.preventDefault();
}
function dropHandler(ev) {
ev.preventDefault();
const data = ev.dataTransfer.getData("text");
ev.target.appendChild(document.getElementById(data));
}
</script>
</head>
<body>
<div id="dropZone"
ondrop="dropHandler(event)"
ondragover="dragoverHandler(event)">
Drop here!
</div>
<br>
<img id="dragImage"
src="https://www.w3schools.com/html/img_w3slogo.gif"
draggable="true"
ondragstart="dragstartHandler(event)"
width="100"
height="50">
</body>
</html>
Expected behaviour: The W3Schools logo image starts below the dashed box. When you drag it and drop it onto the dashed box, it moves inside the box permanently.
3.9 Drag and Drop Back and Forth
You can make two zones where an element can be moved between them in either direction. Just attach ondragover and ondrop handlers to both drop zones:
<div id="zone1" ondrop="dropHandler(event)" ondragover="dragoverHandler(event)">
<img id="myImg" draggable="true" ondragstart="dragstartHandler(event)" src="logo.gif">
</div>
<div id="zone2" ondrop="dropHandler(event)" ondragover="dragoverHandler(event)">
<!-- Drop here to move the image -->
</div>
The exact same three JavaScript functions work for both zones — no changes needed!
3.10 Real-World Uses of Drag and Drop
- Kanban boards (Trello-style task management — drag cards between columns)
- File uploaders (drag files from desktop into a web browser upload zone)
- Image galleries (reorder photos)
- Shopping carts (drag products into the cart)
- Calendar apps (drag events to new time slots)
Part 4 — The HTML5 Web Storage API
4.1 The Problem With Cookies
Before HTML5, if a web page needed to remember something about you (like your name or preferences), it used cookies — small pieces of text stored in your browser. But cookies have big problems:
- They are sent to the server on every single request, even when the server doesn’t need them (slows down your page)
- They can only hold about 4KB of data
- They are hard to work with in JavaScript
Web Storage solves all of these problems.
4.2 What is Web Storage?
The Web Storage API lets web pages store data directly in the user’s browser as simple key-value pairs. It is faster, more secure, and can hold at least 5MB of data — over 1000 times more than cookies.
Web Storage is also per origin — data stored by mywebsite.com can only be read by mywebsite.com. Other websites cannot access it.
4.3 Two Types of Web Storage
| Object | Where Data Lives | When Data Disappears |
|---|---|---|
localStorage |
Browser storage | Never (until user clears browser data) |
sessionStorage |
Browser storage | When the current browser tab is closed |
Think of it this way:
localStorageis like saving a note to a file — it persists foreversessionStorageis like writing on a whiteboard — it disappears when you leave
4.4 Check for Web Storage Support
<script>
const output = document.getElementById("result");
if (typeof(Storage) !== "undefined") {
output.innerHTML = "Great! Your browser supports Web Storage.";
} else {
output.innerHTML = "Sorry, no Web Storage support.";
}
</script>
Output (modern browser): Great! Your browser supports Web Storage.
Why
typeof(Storage) !== "undefined"? We check the type ofStoragerather than justif (Storage)because ifStoragedoesn’t exist, accessing it directly might throw an error.typeofsafely returns the string"undefined"without crashing.
4.5 The localStorage Object — Storing Data
localStorage has three key methods:
setItem(key, value) — saves a key-value pair:
localStorage.setItem("username", "Chidi");
localStorage.setItem("theme", "dark");
getItem(key) — retrieves a value:
let name = localStorage.getItem("username");
console.log(name);
Output: Chidi
removeItem(key) — deletes one item:
localStorage.removeItem("theme");
4.6 A Full localStorage Example
<!DOCTYPE html>
<html>
<body>
<div id="result"></div>
<script>
const output = document.getElementById("result");
if (typeof(Storage) !== "undefined") {
// Store data
localStorage.setItem("lastname", "Smith");
localStorage.setItem("bgcolor", "lightblue");
// Retrieve and display data
output.innerHTML = "Last name: " + localStorage.getItem("lastname");
output.style.backgroundColor = localStorage.getItem("bgcolor");
} else {
output.innerHTML = "Sorry, no Web storage support!";
}
</script>
</body>
</html>
Expected Output:
- The text “Last name: Smith” appears inside a light-blue-coloured
div
Note: Open your browser’s DevTools (F12) → Application tab → Local Storage to see the stored data visually!
Thinking Prompt: What happens if you close the tab, reopen it, and run the
getItem("lastname")line again? Does it still work? Try it!
4.7 Counting Clicks with localStorage
This example demonstrates that data in localStorage persists even after the page is refreshed:
<!DOCTYPE html>
<html>
<body>
<p>You have clicked the button
<strong id="count">0</strong> time(s).</p>
<button onclick="countClick()">Click Me</button>
<script>
// Restore previous count on page load
document.getElementById("count").innerHTML =
localStorage.getItem("clickcount") || 0;
function countClick() {
// Get current count (convert string to number with Number())
let current = Number(localStorage.getItem("clickcount")) || 0;
// Increase by 1 and save
current = current + 1;
localStorage.setItem("clickcount", current);
// Update the display
document.getElementById("count").innerHTML = current;
}
</script>
</body>
</html>
Expected behaviour: Each button click increases the counter. If you refresh the page, the counter continues from where it left off — because the data is stored in localStorage.
Why Number(...)? Everything stored in Web Storage is saved as a string. localStorage.getItem("clickcount") returns "3" (a string), not 3 (a number). Adding "3" + 1 in JavaScript gives "31" (string concatenation), not 4 (addition). Wrapping with Number() converts "3" to 3 first.
4.8 The sessionStorage Object
sessionStorage works exactly like localStorage — same methods (setItem, getItem, removeItem) — but the data vanishes when the browser tab is closed.
<script>
function countSessionClick() {
if (sessionStorage.clickcount) {
sessionStorage.clickcount = Number(sessionStorage.clickcount) + 1;
} else {
sessionStorage.clickcount = 1;
}
document.getElementById("result").innerHTML =
"You clicked " + sessionStorage.clickcount + " time(s) this session!";
}
</script>
Expected behaviour: Click the button several times. The counter works just like localStorage. But close the tab and open the page again — the counter resets to 0!
4.9 Storing Complex Data (Objects)
Web Storage only stores strings. To store an object or array, convert it to JSON first:
// Storing an object
let user = { name: "Amara", age: 25, city: "Lagos" };
localStorage.setItem("user", JSON.stringify(user));
// Retrieving the object
let storedUser = JSON.parse(localStorage.getItem("user"));
console.log(storedUser.name);
Output: Amara
JSON.stringify(user)— converts the object to a string:'{"name":"Amara","age":25,"city":"Lagos"}'JSON.parse(...)— converts the string back to a proper JavaScript object
4.10 Clearing All Storage
// Remove one item
localStorage.removeItem("lastname");
// Remove ALL items
localStorage.clear();
4.11 Real-World Uses of Web Storage
- Remember a user’s dark mode/light mode preference
- Save a partially filled form so it does not disappear on refresh
- Store a user’s reading progress in an article
- Cache data to reduce server requests
- Remember a shopping cart between page visits
Part 5 — The HTML5 Web Workers API
5.1 The Problem — JavaScript is Single-Threaded
Here is something important to understand: by default, JavaScript runs on a single thread. This means it can only do one thing at a time.
Imagine you are cooking and you also need to answer the phone. If cooking requires 100% of your attention, you cannot pick up the phone at all. The same problem happens in JavaScript — if your code is busy doing a heavy calculation, the entire web page freezes. Users cannot click buttons, scroll the page, or do anything until the calculation finishes.
A Web Worker solves this by letting you run JavaScript in a separate background thread — like hiring a second cook to handle the phone while you keep cooking.
5.2 What is a Web Worker?
A Web Worker is a JavaScript file that runs in the background, completely separate from your main page. While the worker is running, users can still interact normally with the page.
Analogy: Think of the main page as a cashier serving customers. The Web Worker is a back-office employee doing heavy paperwork. They work independently without blocking the cashier.
Web workers are useful for:
- Large data calculations
- Image processing
- Sorting massive datasets
- Parsing large files
5.3 What Web Workers Cannot Access
Because workers run in a separate environment, they do not have access to:
- The
windowobject (the browser’s main global object) - The
documentobject (the HTML page’s DOM) - The
parentobject
Workers communicate with the main page only through messages.
5.4 How Workers Communicate — postMessage
Workers and the main page talk to each other using a simple messaging system:
- Main page → Worker:
worker.postMessage(data) - Worker → Main page:
postMessage(data)(called from inside the worker file) - Main page listens to worker:
worker.onmessage = function(event) { ... }
5.5 Step 1 — Create the Worker File
Workers live in a separate .js file. Let us create demo_workers.js:
// demo_workers.js
var i = 0;
function timedCount() {
i = i + 1;
postMessage(i); // Send the current count back to the main page
setTimeout("timedCount()", 500); // Run again after 500 milliseconds
}
timedCount(); // Start counting
Line-by-line:
var i = 0;— a counter variable, starts at 0postMessage(i)— sends the current value ofiback to the main HTML pagesetTimeout("timedCount()", 500)— waits 500ms (half a second) then callstimedCountagaintimedCount()at the end — starts the whole process
5.6 Step 2 — Use the Worker in Your HTML Page
let w; // Will hold our worker object
function startWorker() {
const output = document.getElementById("result");
if (typeof(Worker) !== "undefined") {
// Only create a new worker if one doesn't already exist
if (typeof(w) == "undefined") {
w = new Worker("demo_workers.js"); // Create the worker
}
// Listen for messages from the worker
w.onmessage = function(event) {
output.innerHTML = event.data; // Display the count
};
} else {
output.innerHTML = "Sorry, no Web Worker support in this browser.";
}
}
function stopWorker() {
w.terminate(); // Stop the worker immediately
w = undefined; // Reset so a new one can be created later
}
5.7 The Full Web Worker HTML Page
<!DOCTYPE html>
<html>
<body>
<p>Count: <output id="result"></output></p>
<button onclick="startWorker()">Start Worker</button>
<button onclick="stopWorker()">Stop Worker</button>
<br><br>
<p>Try clicking and scrolling while the worker runs!</p>
<script>
let w;
function startWorker() {
const output = document.getElementById("result");
if (typeof(Worker) !== "undefined") {
if (typeof(w) == "undefined") {
w = new Worker("demo_workers.js");
}
w.onmessage = function(event) {
output.innerHTML = event.data;
};
} else {
output.innerHTML = "Sorry! No Web Worker support.";
}
}
function stopWorker() {
w.terminate();
w = undefined;
}
</script>
</body>
</html>
Expected behaviour:
- Click “Start Worker” → the counter starts updating every half-second
- While counting, scroll the page, click other things — the page stays responsive
- Click “Stop Worker” → counting stops
Thinking Prompt: What would happen to the page if we ran this counting loop in the main page’s JavaScript instead of in a worker?
5.8 Browser Support Check
if (typeof(Worker) !== "undefined") {
// Web Workers are supported
} else {
// No support — show a fallback message
}
5.9 Real-World Uses of Web Workers
- Spell-checking a document (run in background as user types)
- Encoding/decoding video files
- Processing large CSV files without freezing the interface
- Running machine learning predictions in the browser
- Compressing images before upload
Part 6 — The HTML5 Server-Sent Events API
6.1 The Problem — Pages Don’t Update Automatically
Normally, a web page only shows new information when you ask for it — by clicking a button or refreshing the page. But what about live stock prices, news headlines, football scores, or notifications? You want the page to update automatically when the server has new information.
Before Server-Sent Events, developers used messy workarounds like polling (asking the server every few seconds: “Anything new?”). This wastes bandwidth and creates unnecessary server load.
6.2 What are Server-Sent Events?
Server-Sent Events (SSE) allow a server to push (send) updates to a web page automatically whenever new data is available — without the page needing to ask.
Analogy: Traditional requests are like sending a letter and waiting for a reply. SSE is like subscribing to a newspaper — the newspaper arrives at your door every morning without you having to ask.
Key characteristic: SSE is one-way — the server sends to the client. The client cannot send messages back through SSE (for two-way communication, use WebSockets instead).
6.3 The EventSource Object
The SSE API uses the built-in EventSource object. You create one and point it at a server-side script that sends event stream data:
var source = new EventSource("demo_sse.php");
"demo_sse.php"— the URL of a server-side script that generates the stream
6.4 Receiving Messages
You listen for messages using the onmessage event handler:
source.onmessage = function(event) {
document.getElementById("result").innerHTML += event.data + "<br>";
};
event.data— contains the text the server sent+=— appends each new message to the previous ones (so you see a growing list of updates)
6.5 Complete Client-Side SSE Example
<!DOCTYPE html>
<html>
<body>
<h1>Server Updates</h1>
<div id="result"></div>
<script>
const output = document.getElementById("result");
// Check browser support
if (typeof(EventSource) !== "undefined") {
// Connect to the server-side script
var source = new EventSource("demo_sse.php");
// When a message arrives from the server, display it
source.onmessage = function(event) {
output.innerHTML += event.data + "<br>";
};
} else {
output.innerHTML = "Sorry, your browser does not support server-sent events.";
}
</script>
</body>
</html>
Expected behaviour: The page connects to demo_sse.php. Each time the server sends a new message, it appears in the div without any page reload.
6.6 Server-Side Code (PHP)
The server-side script must set the content type to text/event-stream and send data in a specific format:
<?php
// demo_sse.php
// Tell the browser this is an event stream
header('Content-Type: text/event-stream');
// Prevent page caching
header('Cache-Control: no-cache');
// Get the current time
$time = date('r');
// Send the data — MUST start with "data: " and end with "\n\n"
echo "data: The server time is: {$time}\n\n";
// Flush output immediately to the browser
flush();
?>
Line-by-line:
header('Content-Type: text/event-stream')— tells the browser to expect a streaming event feedheader('Cache-Control: no-cache')— prevents the browser from caching the responseecho "data: ..."— sends a message. The format MUST start withdata:and end with TWO newline characters (\n\n)flush()— forces PHP to immediately send the output to the browser rather than buffering it
6.7 Server-Side Code (ASP/VBScript)
<%
Response.ContentType = "text/event-stream"
Response.Expires = -1
Response.Write("data: The server time is: " & now())
Response.Flush()
%>
6.8 The EventSource Object Events
The EventSource object has three events you can listen to:
| Event | When It Fires |
|---|---|
onopen |
When the connection to the server is successfully opened |
onmessage |
When a new message arrives from the server |
onerror |
When a connection error occurs |
source.onopen = function() {
console.log("Connected to server stream.");
};
source.onmessage = function(event) {
console.log("Message received: " + event.data);
};
source.onerror = function() {
console.log("Connection error occurred.");
};
6.9 SSE vs. Web Workers — What is the Difference?
| Feature | Web Workers | Server-Sent Events |
|---|---|---|
| Who initiates? | The web page | The server |
| Where does processing happen? | In the browser (background thread) | On the server |
| Direction | Background task → main page | Server → browser |
| Use case | Heavy JavaScript tasks | Live data updates from server |
6.10 Real-World Uses of Server-Sent Events
- Live news feed updates
- Social media notification counters
- Live sports scores
- Stock market price tickers
- Server-side log monitoring dashboards
- Live auction bid updates
Guided Practice Exercises
Exercise 1 — Geolocation Display
Objective: Build a page that displays the user’s latitude, longitude, and accuracy.
Scenario: You are building a weather app. The first step is to get the user’s coordinates.
Steps:
- Create an HTML page with a button labeled “Find My Location”
- Create a paragraph with
id="locationInfo" - Write a
getLocation()function that callsnavigator.geolocation.getCurrentPosition() - In the success function, display latitude, longitude, and
coords.accuracyin the paragraph - Handle all four error cases
Hint: Access accuracy with position.coords.accuracy.
Expected Output (if user allows):
Latitude: 6.5244
Longitude: 3.3792
Accuracy: 20 metres
Self-check Questions:
- Did you check for browser support before calling
getCurrentPosition? - Did you handle the error cases?
- What unit is
coords.accuracyin?
Exercise 2 — Drag and Drop List Reorder
Objective: Create a list of 3 coloured div boxes that can be dragged and dropped into a target area.
Steps:
- Create three coloured
divelements (e.g., red, blue, green), eachdraggable="true" - Create a drop zone
divwith a dashed border - Wire up
ondragstart,ondragover, andondrop - When a box is dropped into the zone, it should move there
What-if Challenge: Can you modify the code so the boxes can also be dragged back out of the drop zone to their original position?
Exercise 3 — Personal Notes App with localStorage
Objective: Build a simple note-saving app that persists notes even after the page is refreshed.
Scenario: A student wants to save quick study notes in the browser.
Steps:
- Create an
<input>field for the note title - Create a
<textarea>for the note content - Create a “Save Note” button that stores both values in
localStorage - On page load, automatically retrieve and display any previously saved note
- Create a “Clear Note” button that removes the saved note
Expected behaviour: Type a note, click Save. Refresh the page. The note reappears automatically.
Self-check Questions:
- Why must you convert stored numbers back to a number type when doing arithmetic?
- What happens when you call
localStorage.clear()?
Exercise 4 — Temperature Converter Worker
Objective: Create a Web Worker that converts a temperature from Celsius to Fahrenheit.
Worker file (temp_worker.js):
onmessage = function(event) {
const celsius = event.data;
const fahrenheit = (celsius * 9/5) + 32;
postMessage(fahrenheit);
};
Main page:
- Create an
<input>for Celsius value - Create a button “Convert in Worker”
- Create a paragraph to show the Fahrenheit result
- Write JavaScript that creates a worker, sends the Celsius value to it, and displays the result
Expected Output (input: 100):
100°C = 212°F
Mini Project — “Smart Dashboard” Using Multiple APIs
Let us combine everything we have learned into one project: a personal smart dashboard that uses Geolocation, Web Storage, and displays a simulated server update.
Project Overview
The dashboard will:
- Display the user’s coordinates (Geolocation)
- Let users save a personal display name to localStorage
- Show a simulated live clock update (mimicking Server-Sent Events behaviour using
setInterval)
Stage 1 — Setup the HTML Structure
<!DOCTYPE html>
<html lang="en">
<head>
<title>My Smart Dashboard</title>
<style>
body { font-family: Arial, sans-serif; padding: 20px; max-width: 600px; }
.card {
border: 1px solid #ddd;
border-radius: 8px;
padding: 15px;
margin: 15px 0;
background: #f9f9f9;
}
h2 { color: #333; border-bottom: 2px solid #4CAF50; padding-bottom: 5px; }
button {
background: #4CAF50;
color: white;
border: none;
padding: 8px 16px;
border-radius: 4px;
cursor: pointer;
}
input { padding: 6px; margin-right: 8px; border: 1px solid #ccc; border-radius: 4px; }
</style>
</head>
<body>
<h1>🌐 My Smart Dashboard</h1>
<!-- Section 1: Personal Name (Web Storage) -->
<div class="card">
<h2>👤 My Profile</h2>
<input type="text" id="nameInput" placeholder="Enter your name">
<button onclick="saveName()">Save Name</button>
<p>Welcome, <strong id="displayName">Guest</strong>!</p>
</div>
<!-- Section 2: My Location (Geolocation) -->
<div class="card">
<h2>📍 My Location</h2>
<button onclick="getLocation()">Detect My Location</button>
<p id="locationDisplay">Click the button to get your coordinates.</p>
</div>
<!-- Section 3: Live Updates (Simulated SSE) -->
<div class="card">
<h2>🕐 Live Server Time</h2>
<button onclick="startUpdates()">Start Live Updates</button>
<button onclick="stopUpdates()">Stop</button>
<p id="liveTime">Not started yet.</p>
</div>
</body>
</html>
Stage 2 — Add the JavaScript
<script>
// ============ WEB STORAGE SECTION ============
// On page load, restore saved name from localStorage
window.onload = function() {
const savedName = localStorage.getItem("dashboardName");
if (savedName) {
document.getElementById("displayName").innerHTML = savedName;
document.getElementById("nameInput").value = savedName;
}
};
function saveName() {
const name = document.getElementById("nameInput").value;
if (name.trim() !== "") {
localStorage.setItem("dashboardName", name);
document.getElementById("displayName").innerHTML = name;
alert("Name saved! It will still be here after you refresh the page.");
} else {
alert("Please enter a name first.");
}
}
// ============ GEOLOCATION SECTION ============
function getLocation() {
const display = document.getElementById("locationDisplay");
if (navigator.geolocation) {
display.innerHTML = "Detecting location...";
navigator.geolocation.getCurrentPosition(showPosition, showError);
} else {
display.innerHTML = "Geolocation is not supported by this browser.";
}
}
function showPosition(position) {
document.getElementById("locationDisplay").innerHTML =
"📍 Latitude: " + position.coords.latitude.toFixed(4) +
"<br>📍 Longitude: " + position.coords.longitude.toFixed(4) +
"<br>Accuracy: ±" + Math.round(position.coords.accuracy) + " metres";
}
function showError(error) {
const display = document.getElementById("locationDisplay");
switch(error.code) {
case error.PERMISSION_DENIED:
display.innerHTML = "❌ Location access was denied."; break;
case error.POSITION_UNAVAILABLE:
display.innerHTML = "❌ Location information unavailable."; break;
case error.TIMEOUT:
display.innerHTML = "❌ Location request timed out."; break;
default:
display.innerHTML = "❌ Unknown error occurred."; break;
}
}
// ============ SIMULATED SERVER UPDATE SECTION ============
let updateInterval;
function startUpdates() {
if (updateInterval) return; // Don't start a second one
updateInterval = setInterval(function() {
const now = new Date();
document.getElementById("liveTime").innerHTML =
"🕐 Server time: " + now.toLocaleTimeString() +
"<br>📅 Date: " + now.toLocaleDateString();
}, 1000); // Update every second
}
function stopUpdates() {
clearInterval(updateInterval);
updateInterval = undefined;
document.getElementById("liveTime").innerHTML = "Updates stopped.";
}
</script>
Stage 3 — Milestone Check
After building this, you should see:
- A text input where you can type your name, click Save, and have it persist after page refresh
- A location button that shows your coordinates when clicked
- A live-updating time display that can be started and stopped
Reflection Questions
- After saving your name and refreshing the page, where does the
window.onloadfunction get the name from? - Why does
.toFixed(4)inshowPositiondisplay the coordinates with only 4 decimal places? - What is the difference between
setInterval(which we used here) and a real SSE connection? - If you opened a second browser tab for this page, would it see the same stored name? Why?
Optional Enhancements
- Add a “Clear My Data” button that calls
localStorage.clear()and resets the dashboard - Add a drag-and-drop feature that lets users rearrange the three cards
- Connect to a real server-sent events endpoint instead of the simulated timer
Common Beginner Mistakes
Mistake 1 — Forgetting to Check Browser Support
Wrong:
navigator.geolocation.getCurrentPosition(success, error);
// If geolocation isn't supported, this crashes!
Correct:
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(success, error);
} else {
console.log("Geolocation not supported.");
}
Mistake 2 — Forgetting event.preventDefault() in ondragover
Wrong:
function dragoverHandler(ev) {
// Nothing here!
}
// Result: The ondrop event NEVER fires — the drop is blocked.
Correct:
function dragoverHandler(ev) {
ev.preventDefault(); // This is what enables dropping!
}
Mistake 3 — Doing Math on localStorage Strings
Wrong:
localStorage.setItem("count", 1);
let c = localStorage.getItem("count");
c = c + 1; // Result: "11" (string concatenation!) not 2
Correct:
let c = Number(localStorage.getItem("count")) || 0;
c = c + 1; // Result: 2 (arithmetic)
localStorage.setItem("count", c);
Mistake 4 — Trying to Access the DOM From a Web Worker
Wrong (inside worker file):
document.getElementById("result").innerHTML = "done";
// ERROR: document is not defined inside a worker
Correct:
// Workers communicate via messages, not DOM access
postMessage("done"); // Send message to main page
// Main page handles DOM updates in its onmessage handler
Mistake 5 — Using HTTP Instead of HTTPS for Geolocation
Wrong: Testing Geolocation on http://mysite.com — the browser will block it.
Correct: Test on https://mysite.com, or test locally using localhost (which browsers treat as secure).
Mistake 6 — Starting Two Web Workers by Accident
Wrong:
function startWorker() {
w = new Worker("worker.js"); // Creates a new worker every call!
}
Correct:
function startWorker() {
if (typeof(w) == "undefined") { // Only create if none exists
w = new Worker("worker.js");
}
}
Mistake 7 — Forgetting the Double Newline in SSE Data
Wrong (server-side PHP):
echo "data: Hello\n"; // Single newline — browser waits for more
Correct:
echo "data: Hello\n\n"; // Double newline — signals end of one event
Reflection Questions
-
What is the difference between
localStorageandsessionStorage? When would you choose one over the other? -
In the Drag and Drop API, why must
event.preventDefault()be called in theondragoverhandler, not just in theondrophandler? -
Imagine a social media app like Twitter. Which API would be most appropriate for automatically loading new tweets as they are posted — Web Workers or Server-Sent Events? Explain your reasoning.
-
A friend says “I don’t need Web Workers because my computer is fast.” What would you tell them about why Web Workers are still important?
-
What happens to
sessionStoragedata when a user: a) Refreshes the page (F5)? b) Closes the tab? c) Closes the entire browser? -
Why does the Geolocation API require HTTPS? What privacy risk would it pose without it?
-
In the Web Workers API, why can’t a worker access
documentorwindow?
Completion Checklist
Before moving on, confirm that you can:
- Explain what a Web API is and give at least two examples
- State the three golden rules when using any Web API
- Write code that checks for Geolocation support and gets the user’s coordinates
- Handle all four Geolocation error cases by name
- Use
watchPosition()to track continuous location updates - Make an HTML element draggable using the
draggableattribute - Implement the three drag-and-drop handlers (
ondragstart,ondragover,ondrop) - Explain why
event.preventDefault()is required in bothondragoverandondrop - Use
localStorage.setItem()andlocalStorage.getItem()to save and retrieve data - Explain the difference between
localStorageandsessionStorage - Convert stored strings back to numbers before doing arithmetic
- Create a Web Worker
.jsfile withpostMessage()andtimedCount() - Instantiate a Worker, attach
onmessage, and terminate it withterminate() - Explain why Web Workers cannot access
documentorwindow - Create an
EventSourceobject pointing to a server-side script - Handle
onmessage,onopen, andonerrorevents from SSE - Write a PHP SSE endpoint with the correct
Content-Typeheader anddata:format - Distinguish between SSE (server → client) and Web Workers (background thread)
Lesson Summary
In this lesson, you explored the powerful world of HTML5 Web APIs — built-in browser tools that supercharge your web pages with real-world capabilities.
Web APIs are ready-made interfaces built into every modern browser. They let your JavaScript code access complex features without building them from scratch. You learned the three golden rules: always check browser support, add error handling, and request user permission for sensitive data.
The Geolocation API (navigator.geolocation) finds the user’s physical location using GPS, Wi-Fi, or cell towers. getCurrentPosition() retrieves the location once, while watchPosition() tracks it continuously. It only works over HTTPS.
The Drag and Drop API enables users to pick up HTML elements and move them to drop zones. It requires three coordinated event handlers: ondragstart (marks what to drag), ondragover (enables dropping), and ondrop (performs the move). dataTransfer.setData() and getData() carry data between the drag source and drop target.
The Web Storage API provides localStorage (permanent storage) and sessionStorage (tab-session storage) as superior replacements for cookies. Both use the same setItem(), getItem(), and removeItem() methods. Always remember that stored values are strings — use Number() before arithmetic.
The Web Workers API runs JavaScript in a background thread, keeping the page responsive during heavy computations. Workers live in separate .js files, communicate via postMessage() and onmessage, and cannot access the DOM. Use terminate() to stop them.
The Server-Sent Events API lets servers push live updates to web pages using an EventSource connection. The server sends data as text/event-stream content with lines starting with data:. It is perfect for live news feeds, sports scores, stock prices, and notifications.
Together, these APIs are the foundation of dynamic, interactive, and intelligent modern web applications.
Sources: W3Schools HTML5 Web APIs Tutorial (https://www.w3schools.com/html/)