{"id":10612,"library":"carlo","title":"Carlo","description":"Carlo is a Node.js framework designed to create hybrid desktop applications by rendering Node.js data structures and UIs using a locally installed Google Chrome browser instance. It establishes communication between Node.js and the browser via the Puppeteer project, offering a remote call infrastructure for seamless interoperability. Unlike Electron or NW.js, Carlo does not bundle Chromium, relying instead on the user's existing Chrome installation. This approach can lead to smaller application sizes and leverage an up-to-date browser. The project, currently at version 0.9.46, was last updated in June 2019, and its GitHub repository under `GoogleChromeLabs` shows no recent activity, indicating it is no longer actively maintained. Key differentiators included the ability to bundle the application into a single executable using `pkg`, exposing Node.js capabilities to a web frontend, and leveraging the web stack for dynamic visualization of Node.js app states.","status":"abandoned","version":"0.9.46","language":"javascript","source_language":"en","source_url":"https://github.com/GoogleChromeLabs/carlo","tags":["javascript"],"install":[{"cmd":"npm install carlo","lang":"bash","label":"npm"},{"cmd":"yarn add carlo","lang":"bash","label":"yarn"},{"cmd":"pnpm add carlo","lang":"bash","label":"pnpm"}],"dependencies":[{"reason":"Carlo uses `puppeteer-core` internally to establish and manage the connection with the locally installed Chrome browser, and to expose a high-level API for browser control. It is a direct runtime dependency.","package":"puppeteer-core","optional":false},{"reason":"Used for logging and debugging purposes within the Carlo framework.","package":"debug","optional":false}],"imports":[{"note":"Carlo was primarily designed for CommonJS (`require`). While modern bundlers might transpile `import` statements, direct ESM support is not officially provided due to the project's abandoned status and age. The `require` syntax is the idiomatic way to use Carlo.","wrong":"const carlo = require('carlo');","symbol":"carlo","correct":"import carlo from 'carlo'; // (Not officially supported, but may work with bundlers)"},{"note":"The `launch()` function returns a Promise and must be awaited to ensure the browser instance is ready before proceeding.","wrong":"const app = carlo.launch(); // Missing 'await'","symbol":"carlo.launch","correct":"const app = await carlo.launch();"},{"note":"This method also returns a Promise. Awaiting it ensures the function is properly exposed in the browser context before any browser-side calls attempt to use it, preventing race conditions or 'function not found' errors.","wrong":"app.exposeFunction('funcName', (arg) => { /* ... */ }); // Missing 'await' is a common mistake that can lead to race conditions.","symbol":"app.exposeFunction","correct":"await app.exposeFunction('funcName', (arg) => { /* ... */ });"}],"quickstart":{"code":"const carlo = require('carlo');\nconst path = require('path');\n\n(async () => {\n  // Launch the browser. Carlo requires a locally installed Chrome/Chromium.\n  const app = await carlo.launch({\n    args: ['--disable-extensions', '--start-maximized'],\n    width: 800,\n    height: 600\n  });\n\n  // Terminate Node.js process on app window closing.\n  app.on('exit', () => process.exit());\n  app.on('unhandledRejection', (reason, promise) => {\n    console.error('Unhandled Rejection at:', promise, 'reason:', reason);\n  });\n\n  // Serve static web files from the 'app' directory.\n  // Make sure to create a simple `index.html` in a folder named `app`\n  // or serve from `__dirname` if your html is alongside your JS file.\n  app.serveFolder(path.join(__dirname, 'app'));\n\n  // Expose a Node.js function 'getSystemInfo' to the web environment.\n  // This function will be callable from the browser-side JavaScript.\n  await app.exposeFunction('getSystemInfo', async () => {\n    return {\n      nodeVersion: process.version,\n      platform: process.platform,\n      arch: process.arch,\n      envVars: Object.keys(process.env).sort()\n    };\n  });\n\n  // Navigate to the main page of your app.\n  await app.load('index.html');\n\n  console.log('Carlo app launched. Check the new Chrome window.');\n})();\n\n// A minimal app/index.html to be served by Carlo\n// (Save this in a subfolder named 'app' next to your main JS file)\n/*\n<!DOCTYPE html>\n<html>\n<head>\n  <title>Carlo System Info</title>\n  <style>\n    body { font-family: sans-serif; padding: 20px; }\n    pre { background-color: #f4f4f4; padding: 10px; border-radius: 4px; }\n  </style>\n</head>\n<body>\n  <h1>System Information</h1>\n  <pre id=\"info-display\"></pre>\n  <script>\n    async function displaySystemInfo() {\n      const info = await getSystemInfo(); // Call Node.js function\n      document.getElementById('info-display').textContent = JSON.stringify(info, null, 2);\n    }\n    window.onload = displaySystemInfo;\n  </script>\n</body>\n</html>\n*/","lang":"javascript","description":"This quickstart demonstrates launching a Carlo application, serving static HTML content, and exposing a Node.js function (`getSystemInfo`) to the browser environment. The browser-side JavaScript then calls this exposed function to retrieve and display system information from the Node.js process."},"warnings":[{"fix":"Consider migrating to actively maintained alternatives like Electron, NW.js, or Tauri, which provide similar desktop application capabilities with active development and community support.","message":"Carlo is an abandoned project and has not been updated since June 2019. It may not be compatible with newer versions of Node.js, Puppeteer, or Google Chrome. Using it in production environments is highly discouraged due to potential security vulnerabilities, lack of maintenance, and compatibility issues.","severity":"breaking","affected_versions":">=0.9.46"},{"fix":"Ensure Google Chrome (or a compatible Chromium-based browser) is installed on the target system. For specific browser paths, you might need to configure Puppeteer options within Carlo's launch arguments, although this is not directly exposed as a top-level Carlo option.","message":"Carlo relies on a *locally installed* Google Chrome or Chromium browser. If Chrome is not found on the system where the application is run, Carlo will fail to launch with an error message. It does not bundle its own browser like Electron.","severity":"gotcha","affected_versions":">=0.1.0"},{"fix":"If encountering issues, try installing an older version of Chrome (e.g., Chrome 70-75) if possible for development/testing, or inspect Puppeteer's troubleshooting guides for compatibility with older client versions. There is no direct fix within Carlo itself due to its abandoned status.","message":"The `puppeteer-core` dependency in Carlo `0.9.46` is pinned to `~1.12.0`. This old version of Puppeteer may not be compatible with very recent versions of Google Chrome, potentially leading to connection issues or unexpected behavior when Carlo tries to control a modern browser. The 'Chrome Stable channel, versions 70.*' are explicitly mentioned as supported.","severity":"gotcha","affected_versions":">=0.9.0"},{"fix":"Always use `await` when calling Carlo's asynchronous API methods within an `async` function. Ensure proper error handling (e.g., `try...catch` blocks) for these awaited operations.","message":"Carlo's API methods like `launch()`, `exposeFunction()`, `load()`, and `serveFolder()` return Promises. Failing to `await` these promises can lead to race conditions where subsequent operations try to interact with uninitialized browser contexts or functions that haven't been exposed yet, resulting in runtime errors.","severity":"gotcha","affected_versions":">=0.1.0"}],"env_vars":null,"last_verified":"2026-04-19T00:00:00.000Z","next_check":"2026-07-18T00:00:00.000Z","problems":[{"fix":"Install Google Chrome or Chromium on your system. If Chrome is installed in a non-standard location, you might need to specify its executable path in the `carlo.launch()` options, for example: `carlo.launch({ executablePath: '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome' })` (macOS).","cause":"Carlo could not locate an installed Google Chrome or Chromium browser on the system.","error":"Error: Failed to launch the browser process! No browser found at /path/to/chrome. Please download a browser at https://chromium.woolyss.com/ or set 'executablePath' to a browser in 'carlo.launch'."},{"fix":"Ensure `const carlo = require('carlo');` is at the top of your script and that `carlo` is properly installed via `npm install carlo`. Verify your Node.js version meets the `engines` requirement (>=7.6.0).","cause":"The `carlo` module was not correctly imported or required, or the Node.js environment did not properly load it.","error":"TypeError: Cannot read property 'launch' of undefined"},{"fix":"Ensure `await app.exposeFunction('functionName', ...)` completes before any browser-side code attempts to call `functionName()`. Double-check that the function name in `exposeFunction` matches the name used in the browser JavaScript exactly.","cause":"A function exposed from Node.js via `app.exposeFunction` was called from the browser before it was fully registered, or a typo exists in the function name.","error":"ReferenceError: <exposedFunctionName> is not defined at <anonymous>"}],"ecosystem":"npm"}