Our website is made possible by displaying online advertisements to our visitors. Please consider supporting us by disabling your ad blocker.

Monetize Electron Desktop Applications With CoinHive And Angular

So you’ve created an awesome cross-platform desktop application with Electron and are getting a ton of downloads and user activity. Have you thought about what it would take to monetize the application to earn you a bit of money?

Instead of showing annoying ads, you can operate outside of the box and monetize via the resources of your users. Cryptocurrency mining is huge right now, but did you know that it can be done with JavaScript which is what Electron applications are built with?

We’re going to see how to include CoinHive in our cross-platform desktop application built with Electron and mine Monero XMR coins by pooling the computer resources of each user.

While CoinHive can be great for monetizing your applications without charging your users, it is important that you do not use it to be malicious. There are plenty of developers creating malware with CoinHive, but it is up to you to rise above and not take advantage of your users.

The application we plan to build can be seen in the image below.

Mine Monero with CoinHive Using Electron and Angular

As you can see from the above image, we don’t plan to do anything fancy. Chances are, you’ll never have anything about the mining process visible to your user. In our example, we’re going to display the mining progress.

Creating a New Angular Application with the Angular CLI

We’re going to try to keep things as simple as possible. You probably already have your own Electron application ready to go. For this reason, we’re going to see how to add CoinHive to a fresh Angular project.

From the Angular CLI, execute the following:

ng new coinhive-project

We won’t be including any Node.js dependencies for using CoinHive. We will be installing a developer dependency later in this article, but for now, we have a project we can work with.

Getting Started with CoinHive

To use CoinHive in your application, you’re going to need a CoinHive account and a public application key. When your users mine anonymously for you when they use your application, the hashes are sent to CoinHive and after time, you’ll get a payout.

After creating an account, you’ll have access to your CoinHive dashboard. From the Settings tab, click on Sites & API Keys to generate a new key for your application. You can have multiple site keys, and they are for projects, not necessarily sites.

With an application key available, it is time to download the CoinHive SDK. Download the lightweight version of the SDK from the CoinHive website. The version from the CoinHive website does not prompt the user to agree to mining. If you’d like to have prompts, consider the version from AuthedMine.

Assuming you’ve downloaded the CoinHive version, copy the coinhive.min.js file into your project’s src/assets/js directory.

Open the project’s src/index.html file and make it look like the following:

<!doctype html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <title>CoinHive Miner</title>
        <base href="./">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <link rel="icon" type="image/x-icon" href="favicon.ico">
    </head>
    <body>
        <app-root></app-root>
        <script src="assets/js/coinhive.min.js"></script>
    </body>
</html>

We’ve just included the script that we downloaded. At this point in time we can start using CoinHive in our application code.

Developing the Application Logic for Mining Monero in an Electron Application

This application will be a single component application meaning we won’t be using any routers. We’re going to focus on a single HTML file and a single TypeScript file.

Open the project’s src/app/app.component.ts file and include the following TypeScript code:

import { Component, OnInit } from '@angular/core';

declare var CoinHive: any;

@Component({
    selector: 'app-root',
    templateUrl: './app.component.html',
    styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {

    private miner: any;
    public statistics: any;

    public constructor() {
        this.miner = new CoinHive.Anonymous("Eomcy25ZfLfW5EZZqMNrEPxSNFgrRcEm", { throttle: 0.8 });
        this.statistics = {
            hashesPerSecond: 0,
            totalHashes: 0,
            acceptedHashes: 0
        };
    }

    public ngOnInit() {
        this.miner.start();
        this.updateStatistics();
    }

    public updateStatistics() {
        setTimeout(() => {
            this.statistics.hashesPerSecond = this.miner.getHashesPerSecond();
            this.statistics.totalHashes = this.miner.getTotalHashes();
            this.statistics.acceptedHashes = this.miner.getAcceptedHashes();
            this.updateStatistics();
        }, 1000);
    }

}

There is a lot happening in the above code so we need to break it down.

The first thing we should take note of is how we’re declaring the CoinHive class:

declare var CoinHive: any;

Because we’re not using NPM, our TypeScript compiler won’t recognize anything we do and throw errors instead. By declaring the class, we can avoid all this.

Now we have our constructor method:

public constructor() {
    this.miner = new CoinHive.Anonymous("Eomcy25ZfLfW5EZZqMNrEPxSNFgrRcEm", { throttle: 0.8 });
    this.statistics = {
        hashesPerSecond: 0,
        totalHashes: 0,
        acceptedHashes: 0
    };
}

In the constructor method we initialize our variables, including CoinHive with our public site key. We’re also setting a throttle value. The higher the throttle, the less stress will be added on your users CPUs. A 0.8 value means the user will have 80% idle and 20% CPU load. Think of your users and pick a throttle that will work for everyone.

For this example we want to update the UI every second with the mining stats:

public updateStatistics() {
    setTimeout(() => {
        this.statistics.hashesPerSecond = this.miner.getHashesPerSecond();
        this.statistics.totalHashes = this.miner.getTotalHashes();
        this.statistics.acceptedHashes = this.miner.getAcceptedHashes();
        this.updateStatistics();
    }, 1000);
}

The updateStatistics will call itself every second and update our public variable that will be bound to the UI. In your application you probably won’t be showing mining statistics so it probably won’t matter.

Finally we have the ngOnInit method which gets called as part of Angular’s lifecycle hooks:

public ngOnInit() {
    this.miner.start();
    this.updateStatistics();
}

When the application initializes, the miner will start and the statistics will start to update.

The HTML that pairs with the above TypeScript is quite simple. Open the project’s src/app/app.component.html file and include the following markup:

<p>h / s: {{ statistics.hashesPerSecond }}</p>
<p>Total Hashes: {{ statistics.totalHashes }}</p>
<p>Accepted Hashes: {{ statistics.acceptedHashes }}</p>

If you ran your application with ng serve, you could see the mining statistics in your CoinHive dashboard.

Remember, we don’t want a web application, we want a desktop application. This is where Electron comes into play.

Making the Angular Application Desktop Friendly with Electron

With the Angular project ready to go, let’s get Electron support so it can be built into a cross-platform desktop application. From the command line, execute the following from within the project:

npm install electron --save-dev

Electron is now available as a local developer dependency, however, it must be configured as part of our project.

At the root of your project, create an electron.js file with the following JavaScript code:

const {app, BrowserWindow} = require('electron')
const path = require('path')
const url = require('url')

// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let win

function createWindow () {
    // Create the browser window.
    win = new BrowserWindow({width: 800, height: 600})

    // and load the index.html of the app.
    win.loadURL(url.format({
        pathname: path.join(__dirname, 'dist/index.html'),
        protocol: 'file:',
        slashes: true
    }))

    // Open the DevTools.
    //win.webContents.openDevTools()

    // Emitted when the window is closed.
    win.on('closed', () => {
        // Dereference the window object, usually you would store windows
        // in an array if your app supports multi windows, this is the time
        // when you should delete the corresponding element.
        win = null
    })
}

// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.on('ready', createWindow)

    // Quit when all windows are closed.
app.on('window-all-closed', () => {
    // On macOS it is common for applications and their menu bar
    // to stay active until the user quits explicitly with Cmd + Q
    if (process.platform !== 'darwin') {
        app.quit()
    }
})

app.on('activate', () => {
    // On macOS it's common to re-create a window in the app when the
    // dock icon is clicked and there are no other windows open.
    if (win === null) {
        createWindow()
    }
})

// In this file you can include the rest of your app's specific main process
// code. You can also put them in separate files and require them here.

If the above code looks familiar it is because it was taken directly from the Electron Quick Start documentation. However, notice the following block of JavaScript code:

win.loadURL(url.format({
    pathname: path.join(__dirname, 'dist/index.html'),
    protocol: 'file:',
    slashes: true
}))

We’re referencing the dist/index.html file which means we are referencing a built Angular project. For this reason we need to configure our build scripts and our main entry-point in the project’s package.json file. Open the package.json file and include the following:

{
    "name": "coinhive-project",
    "version": "0.0.0",
    "license": "MIT",
    "main": "electron.js",
    "scripts": {
        "ng": "ng",
        "start": "ng serve",
        "build": "ng build --prod",
        "test": "ng test",
        "lint": "ng lint",
        "e2e": "ng e2e",
        "electron": "npm run build; ./node_modules/.bin/electron ."
    },
    "private": true,
    "dependencies": {
        // ..
    },
    "devDependencies": {
        // ...
    }
}

Notice in the electron script we’re building the project, and running it based on the file listed in the main property.

There is one more thing that must be done. We must change our project to use relative paths rather than absolute paths. Since we don’t plan to serve our application, Electron needs to access all resources from a relative path. Open the project’s src/index.html file and change the following line:

<base href="./">

Notice that we’ve prefixed the href with a period to indicate relative paths rather than absolute. When we build, everything will reflect this change.

At this point in time we have an Angular project that can be run within Electron.

Conclusion

You just saw how to earn Monero XMR coins from your Electron and Angular powered desktop applications with CoinHive. By including CoinHive, you can have your users mine Monero every time they use your application rather than showing them advertisements or charging them fees. Obviously the more users, the more you’ll earn, but it is a great alternative to other monetization techniques.

Interested in learning how to create a cryptocurrency wallet with Electron and Angular? Check out my previous article titled, Create a Cross-Platform Desktop DigiByte DGB Wallet with Angular and Electron.

Nic Raboy

Nic Raboy

Nic Raboy is an advocate of modern web and mobile development technologies. He has experience in Java, JavaScript, Golang and a variety of frameworks such as Angular, NativeScript, and Apache Cordova. Nic writes about his development experiences related to making web and mobile development easier to understand.

Search

Follow Us

Support This Site