Web

Fix GamepadListener Not Defined Error in gamepad.js Locally

Resolve 'GamepadListener is not defined' error when running gamepad.js library demo locally. Learn why Gamepad API needs secure context, how to use local server like Python http.server, and correct destructuring implementation.

1 answer 1 view

Why am I getting ‘GamepadListener is not defined’ error when running gamepad.js library demo locally?

I downloaded the demo HTML page and gamepad.js file from the gamepad.js library demo. Both files are in the same directory, and the page opens locally without issues, but this line throws an error:

javascript
const listener = new GamepadListener(); // Error: GamepadListener is not defined

Full HTML code:

html
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8" />
</head>
<body>
gamepad test

<script src="gamepad.js"></script>

<script> 
const listener = new GamepadListener();

listener.on('gamepad:connected', function(event){
 var data = event.detail
 alert(data.index)
})

listener.start();
</script>

</body>
</html>

The demo works on the original website, but not locally. How can I fix this and make the GamepadListener work?

You’re hitting the “GamepadListener is not defined” error because the Gamepad API powering the gamepad.js library only works in secure contexts—like localhost or HTTPS—and opening files directly via file:// doesn’t qualify. Your HTML loads fine visually, but the browser blocks the gamepad functionality to prevent security risks. Quick fix? Serve it from a local server instead of double-clicking the file.


Contents


Understanding the “GamepadListener is not Defined” Error

Picture this: you grab the demo files, toss them in a folder, double-click the HTML, and bam—console screams “GamepadListener is not defined.” Frustrating, right? It works perfectly on the original site, so what’s the catch?

The issue isn’t broken code. Your script tag loads gamepad.js correctly, but when you hit new GamepadListener(), the browser hasn’t made the class available globally. Why? The library relies on the browser’s Gamepad API, which modern browsers (Chrome, Firefox, Safari) aggressively restrict outside secure environments. No secure context, no API access. Result? The library can’t initialize its components, leaving GamepadListener undefined.

Check your browser console fully—it might also warn about “Gamepad API unavailable in insecure context.” This isn’t a bug in gamepad.js; it’s by design. The library’s GitHub repo spells it out: demos fail on file:// protocol.


Why the Gamepad API Requires a Secure Context

Gamepad API isn’t your average JavaScript feature. It accesses real hardware—your controller’s buttons, sticks, vibrations—making it a juicy target for malicious sites. Browsers enforce “secure contexts” to block fingerprinting or unauthorized input grabs.

What counts as secure? HTTPS everywhere, or localhost (127.0.0.1). Your local file? Nope. It’s file://, treated as insecure since Chrome 88 and Firefox 78. The MDN Gamepad API docs confirm: “The API is only available in secure contexts (HTTPS).”

gamepad.js wraps this API with event listeners and fallbacks, but it can’t bypass the restriction. Without it, navigator.getGamepads() returns null, and the library’s exports stay locked. Ever wonder why JS hardware APIs keep tightening up? Privacy wins, but it trips up local devs.

Short version: ditch file://. Your demo needs a server.


How to Fix the Issue Locally

Ready to make it work? Spin up a local server. No fancy setup required—your command line has tools built-in.

Python (easiest if installed):
Open terminal in your demo folder, run:

python -m http.server 8000

Then hit http://localhost:8000 in your browser. Boom—secure context granted.

Node.js (with http-server):

npm install -g http-server
http-server -p 8000

Same deal: http://localhost:8000.

VS Code users: Right-click folder > “Open with Live Server” extension. Instant HTTPS localhost.

Windows no-Python? Use npx serve . if Node’s around.

Test it. Connect a controller, refresh. No more “GamepadListener not defined.” The library initializes because navigator.getGamepads() now responds. Pro tip: Chrome’s gamepad tester at chrome://gamepad-internals/ confirms detection too.

But wait—your code might still need a tweak. More on that next.


Correct Implementation of the gamepad.js Library

Local server solves the context, but peek at the official demo HTML. Notice something? It doesn’t use new GamepadListener() directly.

The library exposes a global gamepad object. Destructure it:

html
<!DOCTYPE HTML>
<html>
<head><meta charset="utf-8" /></head>
<body>
gamepad test

<script src="gamepad.js"></script>

<script> 
const { GamepadListener } = gamepad; // Key line!

const listener = new GamepadListener();

listener.on('gamepad:connected', function(event){
 const data = event.detail;
 alert(`Gamepad ${data.index} connected!`);
});

listener.start();
</script>
</body>
</html>

Your original skipped destructuring, assuming GamepadListener pollutes the global scope. It doesn’t—security-conscious design. Add that line, serve locally, done.

Events like gamepad:connected, gamepad:disconnected, gamepad:buttondown fire reliably now. Pass options to start() for polling rates or recents-only mode if vibration-heavy.


Alternative Solutions and Best Practices

Local server not cutting it? Embed in a full app with Vite or webpack dev server—they default to HTTPS localhost.

For production, host on GitHub Pages or Netlify (free HTTPS). No server wrangling.

Best practices:

  • Always destructure: const { GamepadListener, GamepadEvent } = gamepad;
  • Handle permissions: Some browsers prompt for gamepad access.
  • Polyfill? Nah—stick to native. gamepad.js handles Edge cases.
  • Debug: console.log(gamepad) post-load confirms availability.
  • Cross-browser: Test Firefox (strictest) and Chrome.

Overkill for demos? Sure. But once running, mapping controls feels magical. Controllers detected instantly, no lag.

What if no server ever? Gamepad API won’t budge—it’s non-negotiable.


Sources

  1. gamepad.js GitHub Repository — Official docs on secure context requirements and local server setup for demos: https://github.com/Tom32i/gamepad.js
  2. Gamepad API - MDN Web Docs — Explains secure context rules and Gamepad API availability: https://developer.mozilla.org/en-US/docs/Web/API/Gamepad_API/Using_the_Gamepad_API
  3. gamepad.js Demo HTML — Shows correct destructuring syntax from global gamepad object: https://raw.githubusercontent.com/Tom32i/gamepad.js/master/index.html

Conclusion

The “GamepadListener not defined” gamepad error boils down to insecure file:// access blocking the Gamepad API—serve locally via Python, Node, or Live Server to unlock it. Tweak your code with const { GamepadListener } = gamepad; for proper initialization, and you’re mapping controllers in minutes. Next time a JS hardware lib acts up locally, check that secure context first—saves hours of head-scratching.

Authors
Verified by moderation
Fix GamepadListener Not Defined Error in gamepad.js Locally