217

I'm writing an application using Node.js.

One of the functions I want to create is to open the default web browser and navigate to a specific URL.

I want it to be portable so that it runs on Windows/Mac/Linux.

3
  • 3
    I guess this question is what you're looking for: stackoverflow.com/questions/7664605/… Commented Dec 14, 2011 at 6:49
  • yep, it works in Mac. does it work in Windows and Linux? i didn't have a window machine in hand Commented Dec 14, 2011 at 7:11
  • 1
    xdg-open is working in Linux :) Commented Dec 14, 2011 at 7:16

12 Answers 12

273

Use open (formerly known as opn) because it will handle the cross platform issue. To install:

$ npm install open

To use:

const open = require('open');

// opens the url in the default browser 
open('http://sindresorhus.com');
 
// specify the app to open in 
open('http://sindresorhus.com', {app: 'firefox'});
Sign up to request clarification or add additional context in comments.

10 Comments

ForbesLindesay the callback is being called immediately, instead of when the window is closed. Any ideas?
Not sure, might be worth giving github.com/domenic/opener a try as an alternative module with the same API. It looks like it has a proper issue tracker you could open an issue on. It may just be an oddity of how browsers report the process as ending though, so it may not be easily fixable.
It looks like opener works on Mac / Windows / Linux whereas open only works on Mac / Windows so opener is preferable.
This works for me, but it appears the child process is not detached, so when the server goes down, so does my firefox! Not sure how to get "open" to detach the child process... any idea?
To answer my own question (maybe) it looks like the "opener" package has an "unref()" call that lets you detach. So maybe that's another reason to use "opener" instead of "open" package. Not sure though.
|
103
var url = 'http://localhost';
var start = (process.platform == 'darwin'? 'open': process.platform == 'win32'? 'start': 'xdg-open');
require('child_process').exec(start + ' ' + url);

4 Comments

Should be noted, on windows at least, &'s in the URL should be escaped with ^&
I wrapped similar logic, promisified it and published to npm npmjs.com/package/out-url
Thank you ❤️ less / native dependency free = better
It really worked. Works better with legacy code where we don't have to install dependencies.
11

node-open is deprecated. Now use open:

const open = require('open')

await open('http://sindresorhus.com') // Opens the url in the default browser

await open('http://sindresorhus.com', {app: 'firefox'}) // Specify the app to open in

Comments

9

Windows + Express

app.listen(3000, ()=>{
    require('child_process').exec('start http://localhost:3000/');
});

Comments

7

Install:

$ npm install open

Usage:

const open = require('open');
 
(async () => {
    // Opens the image in the default image viewer and waits for the opened app to quit.
    await open('unicorn.png', {wait: true});
    console.log('The image viewer app quit');
 
    // Opens the URL in the default browser.
    await open('https://sindresorhus.com');
 
    // Opens the URL in a specified browser.
    await open('https://sindresorhus.com', {app: 'firefox'});
 
    // Specify app arguments.
    await open('https://sindresorhus.com', {app: ['google chrome', '--incognito']});
})();

1 Comment

Hi there, thank you for sharing this answer. A link to the documentation on async/await would be nice to add just for reference. Nice comments in the code though :)
6

You may need to implement a switch using the value of ...

require('os').type()

And then use spawn("open") or spawn("xdg-open") depending on the platform?

2 Comments

In windows, i try spawn("explorer.exe",['stackoverflow.com']), the windows explorer will select the default browser to open the URL.
@QingXu awesome! require('child_process').spawn('explorer', ['url']) is a nice oneliner!
6

Simply Use

require('child_process').exec('start https://www.google.co.in/');

It's Worked For me.

Comments

5

The easiest and neatest way, IMHO is using an npm package called openurl. Do a npm install openurl . You could try this real quick in your Nodejs REPL

require("openurl").open("http://stackoverflow.com/questions/8500326/how-to-use-nodejs-to-open-default-browser-and-navigate-to-a-specific-url")

You could also send emails with it if the need arises like so; require("openurl").open("mailto:[email protected]")

Comments

2
#!/usr/bin/env node

const url = 'http://localhost'
require('child_process')
  .exec((process.platform
         .replace('darwin','')
         .replace(/win32|linux/,'xdg-') + 'open ' + url));

2 Comments

Please consider adding a brief explanation of how and why this solves the problem. This will help readers to better understand your solution.
Code only answers are frowned upon on SO and are often downvoted. Context and explanation are usually necessary for understanding the given solution, and to distinguish when your solution should/should not be applied. Answers with explanations are more helpful to future visitors, thus upvoted much more often. SO is designed to be a place to learn how to fix issues. It is also good to indicate the context for which a particular answer applies, such as OS platform, or specific edge cases. Links to documentation or further info are also encouraged (but the actual solution must also be embeded.)
0
var url = '\\index.html';
var start = (process.platform == 'darwin'? 'open': process.platform == 'win32'? 'start': 'xdg-open');
require('child_process').exec(start + ' ' + __dirname + url);

Lexa-B’s answer worked best for me, but I was getting “Windows could not locate index.html” error. I was using lexa-b code child_process exec command to open a local webpage within an npm package I was writing. Needed to open an html file in my npm package when running it / opening it from package bin.js with npx command.

All that was needed was to append __dirname to file path to ensure the relative directory path to the file calling the child_process was correct. The child_process was running at the home folder, which is far away from the npx temp file location. __dirname solves that problem and links the two, solving my missing file error.

Comments

0

The open package now forces you to use import tested as of v10.1.0 in Node.js < 22

I don't understand all the details, there is likely a rationale, but it is extremely annoying that you can't just require anymore, instead you have to:

main.js

import open from 'open'
open('http://example.com')

with mandatory "type": "module", in:

package.json

{
  "name": "test",
  "version": "1.0.0",
  "type": "module",
  "dependencies": {
    "open": "10.1.0"
  }
}

then it worked:

node main.js

If you try:

const open = require('open')
open('http://example.com')

then it fails with:

file:///home/ciro/tmp/open/main.js:1
const open = require('open')
             ^

ReferenceError: require is not defined in ES module scope, you can use import instead
This file is being treated as an ES module because it has a '.js' file extension and '/home/ciro/tmp/open/package.json' contains "type": "module". To treat it as a CommonJS script, rename it to use the '.cjs' file extension.
    at file:///home/ciro/tmp/open/main.js:1:14
    at ModuleJob.run (node:internal/modules/esm/module_job:218:25)
    at async ModuleLoader.import (node:internal/modules/esm/loader:329:24)
    at async loadESM (node:internal/process/esm_loader:34:7)
    at async handleMainPromise (node:internal/modules/run_main:113:12)

Node.js v20.10.0

If you forget the:

"type": "module",

then it fails with:

(node:67598) Warning: To load an ES module, set "type": "module" in the package.json or use the .mjs extension.
(Use `node --trace-warnings ...` to show where the warning was created)
/home/ciro/tmp/open/main.js:1
import open from 'open'
^^^^^^

SyntaxError: Cannot use import statement outside a module
    at internalCompileFunction (node:internal/vm:77:18)
    at wrapSafe (node:internal/modules/cjs/loader:1288:20)
    at Module._compile (node:internal/modules/cjs/loader:1340:27)
    at Module._extensions..js (node:internal/modules/cjs/loader:1435:10)
    at Module.load (node:internal/modules/cjs/loader:1207:32)
    at Module._load (node:internal/modules/cjs/loader:1023:12)
    at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:135:12)
    at node:internal/main/run_main_module:28:49

Node.js v20.10.0

as per: "Uncaught SyntaxError: Cannot use import statement outside a module" when importing ECMAScript 6

Option 2: dynamic import

This works without any changes to anything else:

(async () => {
  const { default: open } = await import('open')
  open('http://example.com')
})()

The default thing is mentioned e.g. at: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/import

Limitations:

Option 3: revert to v8

require break seems to be in v9, so going to v8 is a workaround.

  "dependencies": {
    "open": "8.4.2",

Docs

The README has a warning about this mess:

Warning: This package is native ESM and no longer provides a CommonJS export. If your project uses CommonJS, you will have to convert to ESM or use the dynamic import() function. Please don't open issues for questions regarding CommonJS / ESM.

and it links to: https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c which explains things a bit.

Tested on Node.js v20.10.0, Ubuntu 24.04.

Comments

0

Can be used with import thusly:

import { exec } from "child_process";

exec('start https://www.google.com/');

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.