cf.completefrontendCode editorOpen lab
THE JAVASCRIPT FIELD GUIDE

Device & platform APIs

Use browser device APIs responsibly: clipboard, permissions, geolocation, notifications, and audio or video controls that depend on user trust.

By the end you can
  • 01
    Ask at the right timeUse feature detection and request permissions only after a user action.
  • 02
    Handle refusalMap permission states and geolocation errors to useful UI instead of treating no as failure.
  • 03
    Control mediaUse HTMLMediaElement promises, events, volume, and playback rate safely.

Why device APIs feel different

Most JavaScript you have written so far changes data, the DOM, forms, storage, or network requests. Device and platform APIs cross a more personal boundary: they can read the clipboard, ask where the device is, show system notifications, or start media through speakers and screens. That is useful, but it also touches privacy and attention.

The professional pattern is simple: check support in the real browser, explain the benefit, start from a user action, handle no, and keep a fallback. This lesson uses the same event skills from Introduction to events, the promise skills from Promises, and the Blob idea from the previous Files & Blobs lesson.

Real-life analogyPermissions are a hotel key card

A hotel does not hand every guest a master key at check-in. Each door has a purpose. Browser permissions are the same kind of trust boundary: each capability is separate, and the person using the browser may say no.

In real life: One card opens the gym
In JavaScript: A location grant lets the site use geolocation
In real life: Another door still stays locked
In JavaScript: Location permission does not grant notifications or clipboard reads
In real life: The guest can refuse the card
In JavaScript: The user can choose denied or ignore the prompt
In real life: Staff should explain why they need access
In JavaScript: Good UI asks only when the feature is requested

Where the analogy stops: A hotel card is usually physical and stable. Browser permissions vary by browser, origin, device policy, private mode, and time, so always check the real feature too.

The click-first rule

Every experiment in this lesson starts from a button, paste event, or media control. Nothing asks for clipboard, location, notifications, or playback on page load.

Secure contexts and feature checks

TRUST FIRST

In most browsers, these APIs need a secure context: HTTPS in production or localhost during development. That rule matters because a network attacker should not be able to rewrite a page that asks for your location or clipboard. A framework cannot bypass this; the browser decides.

Support also differs by browser and platform. For browser lessons, that creates a React rule: feature detection happens after mount or after a user action, never during server render. The server does not have navigator, window, permissions, or an audio device, so guessing during render can create hydration mismatches.

Step through a permission-aware request
Step 0 of 5Ready
Your turn: follow the blue line

Pick a feature, predict which messages print, then step through the permission flow.

Running in
  1. script
Next: line 1
Click the blue line to take the next stepPop out in the code editor (opens in a new tab)JavaScript
const state = "prompt"; if (state === "prompt") {  console.log("wait for a click before requesting " + feature);} console.log("explain why the app needs " + feature);
CallStoreChangeResultRun = next line. Ran = already executed.
Recent returnsNothing yet. Start with the blue line.
Choose the feature the app is about to explain.
A guided replay recorded from real JavaScript calls, not an engine debugger. Step follows executed statements; Back reviews a snapshot. Reset starts a fresh run.

The replay is a model of a good permission flow, not a browser debugger. It teaches the shape: name the feature, notice the state is still undecided, wait for the person to click, and explain why before the real request.

Clipboard API: copy, paste, and explicit reads

INTERACTIVE

The Clipboard API lives at navigator.clipboard. The safe, common case is writing text after a click: writeText() returns a promise, so show success only after it resolves and show the real error if it rejects. In some browsers clipboard writing needs transient user activation, which means the call should happen directly from the click handler.

Real-life analogyThe clipboard is a shared tray between apps

The clipboard is not owned by your page. Other apps can use it too, so browsers make your page prove that the person really asked to put something there or take something from it.

In real life: Put a note on the tray
In JavaScript: navigator.clipboard.writeText(text)
In real life: Pick up what someone left
In JavaScript: navigator.clipboard.readText()
In real life: The person places an item into your form
In JavaScript: A paste event with event.clipboardData

Where the analogy stops: A tray is always visible. The system clipboard is private, so browsers may require a user gesture, a prompt, or a paste menu, especially for reads.

Clipboard lab: copy, paste, explicit read
Clipboard patternPop out in the code editor (opens in a new tab)JavaScript
const text = messageInput.value;await navigator.clipboard.writeText(text);status.textContent = "Copied!"; pasteBox.addEventListener("paste", (event) => {  status.textContent = event.clipboardData.getData("text");}); const pasted = await navigator.clipboard.readText();
Real browser clipboardChecking after mount
Current field text(empty)
Try it yourself

Click Copy, paste into the field, or explicitly try Read clipboard.

All clipboard actions start from your click or paste. Feature detection runs after mount so server rendering never guesses about navigator.

Notice the difference between the paste field and the explicit read button. A normal paste event starts with the person choosing Paste, so the event carries the text for that field. readText() asks the browser to hand your page whatever is currently on the shared tray; in most browsers that is more sensitive and may prompt or show a menu.

Permissions without prompting

DASHBOARD

navigator.permissions.query() checks some permission states without showing a prompt. That makes it useful for dashboards, disabled buttons, and helpful explanations. It does not support every name in every browser, so the code catches TypeError and still uses feature detection.

Permissions dashboard: query without prompting
Query several permissionsPop out in the code editor (opens in a new tab)JavaScript
const names = ["geolocation", "notifications", "camera"]; for (const name of names) {  try {    const status = await navigator.permissions.query({ name });    render(name, status.state);    status.addEventListener("change", () => render(name, status.state));  } catch (error) {    render(name, "unsupported");  }}
States here0 checked
Reset cleared the table. Reloading the lesson would query again.
Try it yourself
Feature detecting

This dashboard calls permissions.query() after mount. It does not request access; it only reports what the browser is willing to reveal.

Permission names are intentionally varied. Some browsers throw TypeError for names they do not support.
Permission states and practical UI
StateWhat it meansGood UI response
grantedThe browser says the origin can use the capability.Run the feature, still showing clear controls.
promptThe person has not decided yet, or the browser cannot expose the final answer in advance.Wait until the user clicks the feature, then request.
deniedThe browser or user blocked it.Do not nag. Explain settings and offer a fallback.
Unsupported nameSome browsers throw TypeError for permission names they do not know.Catch it and check the real feature another way.

The returned PermissionStatus can fire a change event. That matters when someone changes a browser setting while your page is open. Do not treat prompt as permission; it means “ask later, when the person actually wants this feature.”

Geolocation: ask where we are

INTERACTIVE

navigator.geolocation.getCurrentPosition() accepts three arguments: a success callback, an error callback, and options. The result gives latitude, longitude, and accuracy in meters. The options shape the trade-off: enableHighAccuracy may be slower or use more power, timeout limits waiting, and maximumAge says how old a cached answer may be.

Real-life analogyGeolocation is asking a passer-by where we are

You can ask politely, but you cannot demand a perfect answer. Good apps make refusal and rough answers part of the design.

In real life: They can refuse to answer
In JavaScript: Error code 1: PERMISSION_DENIED
In real life: They can point roughly down the street
In JavaScript: Coordinates plus an accuracy radius
In real life: They might take too long
In JavaScript: Error code 3: TIMEOUT
In real life: They remember a recent answer
In JavaScript: maximumAge allows cached positions

Where the analogy stops: A browser may combine GPS, Wi-Fi, IP address, and platform policy. It is not literally one passer-by, and the answer may be unavailable.

Geolocation lab: ask, wait, or simulate
Geolocation requestPop out in the code editor (opens in a new tab)JavaScript
navigator.geolocation.getCurrentPosition(  (position) => {    const { latitude, longitude, accuracy } = position.coords;    show(formatCoordinates(latitude, longitude, accuracy));  },  (error) => show(mapGeolocationError(error.code)),  { enableHighAccuracy: true, timeout: 8000, maximumAge: 60000 },);
Location resultChecking after mount

Click Share my location, or use the simulated success path if you prefer not to share.

Try it yourself

Click Share my location, or use the simulated success path if you prefer not to share.

The lab never stores or sends coordinates. The simulated path lets you learn without revealing a real location.

This lesson rounds coordinates to two decimals so examples stay readable. Real apps should be clear about whether they need exact location, approximate region, or a manual city. The lab never stores or sends coordinates, and the simulated path is there for readers who decline.

Notifications: ask only when the feature makes sense

CLICK ONLY

The Notifications API has its own state at Notification.permission: granted, denied, or default. The request method is Notification.requestPermission(), and it should run only after the person chooses a notification feature.

Notifications lab: ask on click
Notification requestPop out in the code editor (opens in a new tab)JavaScript
if (Notification.permission === "default") {  const permission = await Notification.requestPermission();  if (permission === "granted") {    new Notification("Device APIs lab", { body: "Thanks for opting in." });  }}
Notification.permissionunknown

Check another way

Try it yourself

Click the button to request permission only if you want to test notifications.

Real apps usually pair notification permission with a service worker for push. Some platforms allow web notifications only for installed apps.

A page can create a test notification while it is open. Real apps often use a service worker for push notifications so messages can arrive when the page is not focused. Some platforms restrict web notifications even more, for example allowing them only for installed web apps. When behavior varies, say “in most browsers” instead of pretending every platform is identical.

Audio and video: one media API

LIVE AUDIO

An <audio> or <video> element is an HTMLMediaElement. It has methods like play() and pause(), properties like currentTime, volume, and playbackRate, plus events such as play, pause, timeupdate, and ended.

Real-life analogyA media element is a TV remote

You send commands, but the device still reports whether those commands worked. That is why play() gives you a promise and media events keep the interface synced.

In real life: Press Play
In JavaScript: Call audio.play() and await the promise
In real life: The TV refuses to start with sound
In JavaScript: The promise can reject with NotAllowedError
In real life: Change volume or speed
In JavaScript: Set volume or playbackRate
In real life: The TV reports what happened
In JavaScript: Listen for play, pause, timeupdate, and ended

Where the analogy stops: A remote does not know browser autoplay policy, codecs, or muted playback rules. A media element does, so handle promises and events.

Media lab: generated audio, promises, events
Media controlsPop out in the code editor (opens in a new tab)JavaScript
const audio = document.querySelector("audio"); try {  await audio.play();  log("play() resolved");} catch (error) {  log(error.name);} audio.volume = 0.4;audio.playbackRate = 1.25;audio.addEventListener("timeupdate", updateClock);
Generated audiogenerated locally
Volume0.35
Playback rate1×
Current time0.00s
Event log
  1. Audio Blob will be created after mount.
Try it yourself

currentTime is 0.00s. Audio Blob will be created after mount.

The page builds a tiny WAV Blob in code: no external media request. A video element uses the same HTMLMediaElement methods and events.

The lab generates a tiny WAV file in the page with a Blob URL, so it does not fetch external media. Autoplay rules are why the Play button matters: in most browsers, trying to start unmuted media without a user gesture can reject with NotAllowedError. A video element shares the same core API.

Where you’ll use this

SORTER

Product code often starts with a sentence, not an API name: “copy the invite link,” “show nearby classrooms,” “remind me when export is done,” or “slow down the lesson video.” Sort by what the task touches, then ask what permission or user gesture is required.

Which browser capability fits the task?
  • Copy an invite link after the user presses Share
  • Let a learner paste a coupon into a field
  • Find workshops near the reader’s current city
  • Show “about 30 m accuracy” beside a map dot
  • Remind someone when a long export finishes
  • Ask once before sending calendar reminder alerts
  • Play a confirmation chime generated in the page
  • Let a learner slow a tutorial video to 0.75×
Try it yourself
0 of 8 correct

Choose the API family for each realistic task.

Choose a category for every card. You can change an answer at any time; Reset clears them all.
A reusable request checklist
  • Can the app still work if the person says no?
  • Can this start from a click, paste, or media control?
  • Does this browser support the API in this secure context?
  • What exact error or permission state will the UI show?

Common misconceptions

PITFALLS
  • “Permission is global.” Permission is per capability and usually per origin. Location does not grant notifications.
  • “prompt means I can use it.” It means the browser has not received a final answer. Ask only from a relevant action.
  • “permissions.query tells me everything.” Names vary by browser; unsupported names can throw. Feature-detect too.
  • “Geolocation is exact.” Coordinates include an accuracy radius and can be stale, unavailable, or denied.
  • “play() always starts sound.” The promise can reject because of autoplay policy, missing data, or unsupported media.
  • “Clipboard reads are the same as paste.” A paste event is user-initiated; explicit clipboard reads are more sensitive.

Practice exercises

5 EXERCISES
Exercise 1 · Warm-upMap the timeout code

Predict the exact text printed by this geolocation error helper.

Starter codePop out in the code editor (opens in a new tab)JavaScript
function messageFor(code) {
  if (code === 1) return "Permission denied";
  if (code === 2) return "Position unavailable";
  if (code === 3) return "Timeout";
  return "Unknown";
}
console.log(messageFor(3));

Answer, then press Check. Spacing and letter case don’t matter.

    Exercise 2 · PracticeRound friendly coordinates

    Predict the Mumbai coordinate display for the starter code.

    Starter codePop out in the code editor (opens in a new tab)JavaScript
    function rounded(lat, lon) {
      return lat.toFixed(2) + ", " + lon.toFixed(2);
    }
    console.log(rounded(19.076, 72.8777));

    Answer, then press Check. Spacing and letter case don’t matter.

      Exercise 3 · PracticeHandle denied permission

      Predict the message for a denied permission state.

      Starter codePop out in the code editor (opens in a new tab)JavaScript
      function shouldAsk(state) {
        return state === "prompt" ? "ask on click" : "do not prompt";
      }
      console.log(shouldAsk("denied"));

      Answer, then press Check. Spacing and letter case don’t matter.

        Exercise 4 · PracticeWrite a click-first clipboard handler

        Write the missing code for a copy button in your editor or console. Keep the request inside the click handler.

        Starter codePop out in the code editor (opens in a new tab)JavaScript
        button.addEventListener("click", async () => {
          // copy inviteLink here
        });
          Exercise 5 · ChallengeMake media refusal friendly

          Fix this media starter so a blocked play request becomes useful UI.

          Starter codePop out in the code editor (opens in a new tab)JavaScript
          async function startAudio(audio, status) {
            await audio.play();
            status.textContent = "Playing";
          }

            Check your understanding

            7 QUESTIONS
            Device APIs quiz · 7 questionsScore: first tries count
            1. Question 1 of 7Which statement best describes secure contexts for these APIs?

              Choose an answer to see the explanation.

            2. Question 2 of 7What does the coordinate formatter output for Mumbai?

              Read the code, then predictPop out in the code editor (opens in a new tab)JavaScript
              function formatCoordinates(latitude, longitude, accuracy) {
                return latitude.toFixed(2) + ", " + longitude.toFixed(2) + " (about " + Math.round(accuracy) + " m accuracy)";
              }
              console.log(formatCoordinates(19.076, 72.8777, 28.6));

              Choose an answer to see the explanation.

            3. Question 3 of 7Which geolocation error code means timeout?

              Choose an answer to see the explanation.

            4. Question 4 of 7What should happen before calling Notification.requestPermission()?

              Choose an answer to see the explanation.

            5. Question 5 of 7What does play() give you on a media element?

              Choose an answer to see the explanation.

            6. Question 6 of 7What does this permission helper print?

              Read the code, then predictPop out in the code editor (opens in a new tab)JavaScript
              function permissionBadge(state) {
                return state === "granted" ? "Allowed" : state === "denied" ? "Blocked" : state === "prompt" ? "Ask on use" : "Check another way";
              }
              console.log(permissionBadge("unsupported"));

              Choose an answer to see the explanation.

            7. Question 7 of 7Which API is the best fit for a Paste button that reads text only after the click?

              Choose an answer to see the explanation.

            Key takeaways

            • Powerful browser APIs usually require a secure context and real browser feature detection.
            • Permission prompts belong behind user intent, not page load.
            • Clipboard reads, geolocation, notifications, and media playback all have normal failure paths.
            • Geolocation includes accuracy and error codes; never assume exact coordinates.
            • HTMLMediaElement powers both audio and video with promises, properties, and events.

            Final definition.
            Device and platform APIs are browser-controlled bridges to user-sensitive capabilities, so good JavaScript checks support, asks at the right moment, and handles refusal with care.

            Up next: Web Workers.

            CompleteFrontend Clear concepts. Working examples.