Push Notifications vs Polling in LINEJS: Real-Time Event Handling

Push notifications in LINEJS use a persistent TCP/HTTP-2 connection to stream events instantly from the server, while polling repeatedly calls HTTP APIs on a fixed timer to fetch batches of events.

The evex-dev/linejs library provides two distinct mechanisms for receiving Talk and Square events. Understanding the difference between push notifications and polling in LINEJS is essential for building efficient applications that minimize latency and server load. The source code clearly delineates these approaches across separate architectural layers.

How Push Notifications Work in LINEJS

Push notifications establish a long-lived connection that allows the LINE server to deliver events as they occur.

The Persistent Connection Architecture

In packages/linejs/base/push/connManager.ts, the initializeConn() method opens a single socket to the /PUSH/1/subs?m=${m} endpoint. The parameter m encodes the requested services: Talk = 5 and Square = 3. This connection remains open indefinitely, enabling the server to push event frames down to the client immediately upon generation without repeated handshakes.

Stream-Based Event Consumption

The client wraps incoming frames in ReadableStream instances (opStream for Talk operations, sqStream for Square events). You consume these using standard async iteration. The _OnPushResponse() function in connManager.ts parses each frame and dispatches it to the appropriate stream writer.

How Polling Works in LINEJS (Deprecated)

Polling represents the legacy approach and is explicitly marked as deprecated in the source code.

Timer-Based HTTP Requests

Located in packages/linejs/base/polling/mod.ts, the private async generators _listenTalkEvents() and _listenSquareEvents() implement the polling strategy. These generators repeatedly call standard HTTP service methods—client.talk.sync() and client.square.fetchMyEvents()—followed by await sleep(pollingInterval). The default intervals are 100 ms for Talk and 1000 ms for Square.

Unlike push, polling maintains no persistent connection. Each iteration opens a new HTTP request, returns accumulated events, then pauses until the next timer tick, creating higher latency and bandwidth overhead.

Key Differences: Push vs Polling

Feature Push Notifications Polling (Deprecated)
Connection Single persistent TCP/HTTP-2 socket to /PUSH Repeated HTTP connections
Latency Real-time delivery Delayed by polling interval
Resource Usage Lower bandwidth, one connection Higher overhead per request
Entry Point client.poll.listenTalkEvents() client.createPolling().listenTalkEvents()
Implementation ConnManager.initializeConn(), _OnPushResponse() Private generators _listenTalkEvents(), _listenSquareEvents()
Status Recommended default Deprecated, backward compatibility only

Code Examples

The push approach uses client.poll, which internally initializes the connection via initLegyPusher() and returns a ReadableStream.

import { Client } from "@evex/linejs";

async function main() {
  const client = new Client({
    device: "iOS",
    version: "14.0",
  });
  await client.login();

  // Returns a ReadableStream backed by the push connection
  const talkStream = client.poll.listenTalkEvents();

  for await (const op of talkStream) {
    console.log("Talk operation:", op);
  }
}
main();

Execution path: listenTalkEvents() → initLegyPusher() → ConnManager.initializeConn() → opStream writer enqueue.

Receiving Events via Deprecated Polling

Use createPolling() to instantiate a fresh polling instance. This invokes the private _listenTalkEvents() generator.

import { Client } from "@evex/linejs";

async function main() {
  const client = new Client({ device: "iOS" });
  await client.login();

  const polling = client.createPolling();
  
  // Uses the deprecated polling generator
  for await (const op of polling.listenTalkEvents()) {
    console.log("Polled operation:", op);
  }
}
main();

Execution path: _listenTalkEvents() → client.talk.sync() → sleep(pollingInterval) → loop.

Summary

  • Push notifications in LINEJS use a persistent /PUSH connection via ConnManager to stream events in real-time through ReadableStream interfaces (opStream, sqStream).
  • Polling repeatedly calls talk.sync() and square.fetchMyEvents() with fixed delays (100ms/1000ms), consuming more bandwidth and introducing latency.
  • The push implementation resides in packages/linejs/base/push/connManager.ts and is accessed through client.poll.listenTalkEvents().
  • Polling generators in packages/linejs/base/polling/mod.ts are marked @deprecated and should only be used when persistent connections are impossible.
  • Push is the default for new applications; polling remains available solely for backward compatibility in restricted network environments.

Frequently Asked Questions

What is the primary technical difference between push and polling in LINEJS?

Push maintains a single long-lived TCP/HTTP-2 connection to the /PUSH endpoint where the server streams events immediately, while polling opens new HTTP connections repeatedly on a timer to fetch batched events. According to the evex-dev/linejs source, push uses ConnManager.initializeConn() for the persistent socket, whereas polling uses private async generators with sleep() delays.

Why is polling marked as deprecated in the LINEJS codebase?

Polling is deprecated because it creates unnecessary server load through repeated HTTP handshakes and introduces latency based on the polling interval. The push implementation delivers events instantly and conserves bandwidth, making it the superior architecture for real-time applications.

How do I switch from polling to push notifications in my LINEJS application?

Replace client.createPolling().listenTalkEvents() with client.poll.listenTalkEvents(). The client.poll property automatically initializes the push connection via initLegyPusher() and returns ReadableStream instances that you consume with for await...of loops. No additional configuration is required beyond standard client initialization.

Can I use both push notifications and polling simultaneously?

While technically possible by creating separate instances, it is not recommended. The ConnManager handles event deduplication and connection state; running both methods simultaneously against the same account could cause event processing conflicts and increase server load unnecessarily.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →