Electron has two processes named IPC Main and IPC Renderer for sending data between each other.
IPC Renderer usually called from the web page. It sends a request to the IPC Main which processes data and gives a response back.
    IPC Renderer -> IPC Main -> IPC Renderer
This way you can transfer data between window and main process.
Code
Code examples are available in Electron Documentation: ipcMain.
Main process
const { ipcMain } = require('electron');
/** Define channel name and message */
const CHANNEL_NAME = 'main';
const MESSAGE = 'pong';
/**
 * SYNCHRONOUS
 */ 
ipcMain.on(CHANNEL_NAME, (event, data) => {
  console.log(data); // show the request data
  event.returnValue = MESSAGE; // send a response for a synchronous request
});
/**
 * ASYNCHRONOUS
 */ 
ipcMain.on(CHANNEL_NAME, (event, data) => {
  console.log(data); // show the request data
  event.reply(CHANNEL_NAME, MESSAGE) // callback with a response for an asynchronous request
});
Web page
const { ipcRenderer } = require('electron');
/** Define channel name and message */
const CHANNEL_NAME = 'main';
const MESSAGE = 'ping';
  
/**
 * SYNCHRONOUS
 */  
console.log(ipcRenderer.sendSync(CHANNEL_NAME, MESSAGE)); // send request and show response 
/**
 * ASYNCHRONOUS
 */  
ipcRenderer.send(CHANNEL_NAME, message); // send request
ipcRenderer.on(CHANNEL_NAME, (event, data) => { // IPC event listener
  console.log(data); // show the response data
});
Examples
    Here is a package.json file for our sample Electron app.
{
  "main": "main.js",
  "scripts": {
    "start": "electron ."
  },
  "devDependencies": {
    "electron": "^5.0.1"
  }
}
    Create this file and run npm start to install required packages.
    Then create a main.js script for the app.
const { app, BrowserWindow, ipcMain } = require('electron');
/**
 * Create a new window
 */
const createWindow = () => {
  let mainWindow = new BrowserWindow({
    webPreferences: {
      /** Enable node integration */
      nodeIntegration: true
    }
  });
  /** Open devTools */
  mainWindow.webContents.openDevTools();
  /** Load the index.html page */
  mainWindow.loadFile('index.html');
};
/**
 * Initialize the application
 */
const init = () => {
  /** Create app window */
  createWindow();
  
  /** Define channel name */
  const CHANNEL_NAME = 'main';
  
  /**
   * Add an IPC event listener for the channel
   */ 
  ipcMain.on(CHANNEL_NAME, (event, data) => {
    /** Show the request data */
    console.log(data);
    
    /** Send a response for a synchronous request */
    event.returnValue = 'pong';
  })
};
/**
 * Run the app
 */
app.on('ready', init);
    And the last file is an index.html page.
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>IPC test app</title>
    <script>
        const { ipcRenderer } = require('electron');
        /** Define channel name */
        const CHANNEL_NAME = 'main';
        /** Create a processor for a button's click event */
        const clickButton = () => {
          /** Message to be sent */
          let message = 'ping';
          /** Show response for a sync IPC request */
          console.log(ipcRenderer.sendSync(CHANNEL_NAME, message));
        }
    </script>
</head>
<body>
    <button onclick="clickButton()">Press me</button>
</body>
</html>
    Now you can run this Electron app by the simple command npm start.
You will see a browser window with a one button on the page. Click it.
    In the terminal with a running script ping will be shown. Also pong will be appeared in the browser's console.
 
    
    Asynchronous requests
You can also send and process async requests.
    Updated main.js file.
const { app, BrowserWindow, ipcMain } = require('electron');
let mainWindow;
/**
 * Create a new window
 */
const createWindow = () => {
  mainWindow = new BrowserWindow({
    webPreferences: {
      /** Enable node integration */
      nodeIntegration: true
    }
  });
  /** Open devTools */
  mainWindow.webContents.openDevTools();
  /** Load the index.html page */
  mainWindow.loadFile('index.html');
};
/**
 * Initialize the application
 */
const init = () => {
  /** Create app window */
  createWindow();
  /** Define channel name */
  const CHANNEL_NAME = 'main';
  
  /**
   * Add an IPC event listener for the channel
   */
  ipcMain.on(CHANNEL_NAME, (event, data) => {
    /** Show the request data */
    console.log(data);
    /** Callback with a response for an asynchronous request */
    event.reply(CHANNEL_NAME, 'pong')
  })
};
/**
 * Run the app
 */
app.on('ready', init);
    Updated index.html file.
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>IPC test app</title>
    <script>
      const { ipcRenderer } = require('electron');
      /** Define channel name */
      const CHANNEL_NAME = 'main';
      /** Add IPC event listener */
      ipcRenderer.on(CHANNEL_NAME, (event, data) => {
        console.log(data);
      });
      /** Create a processor for a button's click event */
      const clickButton = () => {
        /** Message to be sent */
        let message = 'ping';
        /** Send async request without waiting answer */
        ipcRenderer.send(CHANNEL_NAME, message)
      }
    </script>
</head>
<body>
    <button onclick="clickButton()">Press me</button>
</body>
</html>
ipcMain to ipcRenderer
    You can send data from ipcMain to ipcRenderer manually without waiting for a response via send() method of windows's content.
    mainWindow is an instance of a BrowserWindow.
const CHANNEL_NAME = 'main';
const MESSAGE = 'tick';
setInterval(() => {
  mainWindow.webContents.send(CHANNEL_NAME, MESSAGE);
}, 1000);
You can handle this event on the web page by ipcRenderer.
const CHANNEL_NAME = 'main';
ipcRenderer.on(CHANNEL_NAME, (event, data) => {
  console.log(data);
});
Example
    main.js file.
const { app, BrowserWindow, ipcMain } = require('electron');
/** Define window's variable in the global scope */
let mainWindow;
/**
 * Create a new window
 */
const createWindow = () => {
  mainWindow = new BrowserWindow({
    webPreferences: {
      /** Enable node integration */
      nodeIntegration: true
    }
  });
  /** Open devTools */
  mainWindow.webContents.openDevTools();
  /** Load the index.html page */
  mainWindow.loadFile('index.html');
};
/**
 * Initialize the application
 */
const init = () => {
  /** Create app window */
  createWindow();
  /** Define channel name and message */
  const CHANNEL_NAME = 'main';
  const MESSAGE = 'tick';
  /** Send message every one second */
  setInterval(() => {
    mainWindow.webContents.send(CHANNEL_NAME, MESSAGE);
  }, 1000);
};
/**
 * Run the app
 */
app.on('ready', init);
    index.html file.
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>IPC test app</title>
    <script>
      const { ipcRenderer } = require('electron');
      /** Define channel name */
      const CHANNEL_NAME = 'main';
      /** Add IPC event listener */
      ipcRenderer.on(CHANNEL_NAME, (event, data) => {
        console.log(data);
      });
    </script>
</head>
<body>
</body>
</html>
