> ## Documentation Index
> Fetch the complete documentation index at: https://docs.chainstack.com/llms.txt
> Use this file to discover all available pages before exploring further.

# eth_unsubscribe | Hyperliquid EVM

> Cancel an active WebSocket subscription on Hyperliquid EVM. Stop receiving notifications for a previously established subscription.

<Info>
  This method is available on Chainstack. Not all Hyperliquid methods are available on Chainstack, as the open-source node implementation does not support them yet — see [Hyperliquid methods](/docs/hyperliquid-methods) for the full availability breakdown.
</Info>

The `eth_unsubscribe` JSON-RPC method allows developers to cancel an active WebSocket subscription on the Hyperliquid EVM blockchain. This method is used to stop receiving notifications for subscriptions created with `eth_subscribe`, helping to manage resources and control data flow in applications.

<Check>
  **Get your own node endpoint today**

  [Start for free](https://console.chainstack.com/) and get your app to production levels immediately. No credit card required.

  You can sign up with your GitHub, X, Google, or Microsoft account.
</Check>

## Parameters

1. **subscription ID** (string, required): The subscription identifier returned by `eth_subscribe` when the subscription was created

## Response

The method returns a boolean value indicating whether the unsubscribe operation was successful.

### Response structure

* `true` — the subscription was successfully cancelled
* `false` — the subscription was not found or could not be cancelled

## Usage example

### Basic implementation

<Info>
  Note that subscriptions require a WebSocket connection. Install WebSocket cat for testing:

  ```bash theme={"system"}
  npm install -g wscat
  ```
</Info>

```shell wscat theme={"system"}
$ wscat -c wss://hyperliquid-mainnet.core.chainstack.com/4f8d8f4040bdacd1577bff8058438274/evm
# Wait for the connection to be established

Connected (press CTRL+C to quit)

# First create a subscription
> {"id":1,"jsonrpc":"2.0","method":"eth_subscribe","params":["newHeads"]}
< {"jsonrpc":"2.0","id":1,"result":"0x1234567890abcdef"}

# Now unsubscribe using the subscription ID
> {"id":2,"jsonrpc":"2.0","method":"eth_unsubscribe","params":["0x1234567890abcdef"]}
< {"jsonrpc":"2.0","id":2,"result":true}
```

### JavaScript implementation with subscription management

```javascript theme={"system"}
const WebSocket = require('ws');

const CHAINSTACK_WSS_URL = 'wss://hyperliquid-mainnet.core.chainstack.com/YOUR_ENDPOINT/evm';

class SubscriptionManager {
  constructor(wsUrl) {
    this.wsUrl = wsUrl;
    this.ws = null;
    this.subscriptions = new Map();
    this.requestId = 0;
  }

  connect() {
    return new Promise((resolve, reject) => {
      this.ws = new WebSocket(this.wsUrl);
      
      this.ws.on('open', () => {
        console.log('Connected to Hyperliquid EVM WebSocket');
        resolve();
      });
      
      this.ws.on('message', (data) => {
        this.handleMessage(JSON.parse(data));
      });
      
      this.ws.on('error', (error) => {
        console.error('WebSocket error:', error);
        reject(error);
      });
      
      this.ws.on('close', () => {
        console.log('WebSocket connection closed');
        this.subscriptions.clear();
      });
    });
  }

  async subscribe(type, params = []) {
    const id = ++this.requestId;
    
    return new Promise((resolve) => {
      const request = {
        id,
        jsonrpc: '2.0',
        method: 'eth_subscribe',
        params: [type, ...params]
      };
      
      // Store resolver to handle response
      this.subscriptions.set(`request_${id}`, {
        type: 'request',
        resolve,
        subscriptionType: type
      });
      
      this.ws.send(JSON.stringify(request));
      console.log(`Subscribing to ${type}...`);
    });
  }

  async unsubscribe(subscriptionId) {
    const id = ++this.requestId;
    
    return new Promise((resolve) => {
      const request = {
        id,
        jsonrpc: '2.0',
        method: 'eth_unsubscribe',
        params: [subscriptionId]
      };
      
      // Store resolver to handle response
      this.subscriptions.set(`request_${id}`, {
        type: 'unsubscribe',
        resolve,
        subscriptionId
      });
      
      this.ws.send(JSON.stringify(request));
      console.log(`Unsubscribing from ${subscriptionId}...`);
    });
  }

  handleMessage(message) {
    // Handle subscription/unsubscription responses
    if (message.id) {
      const request = this.subscriptions.get(`request_${message.id}`);
      if (request) {
        if (request.type === 'request') {
          // Store the subscription ID
          this.subscriptions.set(message.result, {
            type: 'subscription',
            subscriptionType: request.subscriptionType,
            handler: null
          });
          console.log(`Subscribed with ID: ${message.result}`);
          request.resolve(message.result);
        } else if (request.type === 'unsubscribe') {
          // Clean up subscription
          if (message.result === true) {
            this.subscriptions.delete(request.subscriptionId);
            console.log(`Successfully unsubscribed from ${request.subscriptionId}`);
          } else {
            console.log(`Failed to unsubscribe from ${request.subscriptionId}`);
          }
          request.resolve(message.result);
        }
        this.subscriptions.delete(`request_${message.id}`);
      }
    }
    
    // Handle subscription notifications
    if (message.method === 'eth_subscription') {
      const subscription = this.subscriptions.get(message.params.subscription);
      if (subscription && subscription.handler) {
        subscription.handler(message.params.result);
      }
    }
  }

  setHandler(subscriptionId, handler) {
    const subscription = this.subscriptions.get(subscriptionId);
    if (subscription) {
      subscription.handler = handler;
    }
  }

  async disconnect() {
    // Unsubscribe from all active subscriptions
    const activeSubscriptions = Array.from(this.subscriptions.entries())
      .filter(([_, sub]) => sub.type === 'subscription')
      .map(([id, _]) => id);
    
    for (const subId of activeSubscriptions) {
      await this.unsubscribe(subId);
    }
    
    this.ws.close();
  }
}

// Example usage
async function main() {
  const manager = new SubscriptionManager(CHAINSTACK_WSS_URL);
  
  try {
    await manager.connect();
    
    // Subscribe to new blocks
    const blockSubId = await manager.subscribe('newHeads');
    manager.setHandler(blockSubId, (block) => {
      console.log(`New block: ${parseInt(block.number, 16)}`);
    });
    
    // Subscribe to logs
    const logSubId = await manager.subscribe('logs', [{
      address: '0x5555555555555555555555555555555555555555'
    }]);
    manager.setHandler(logSubId, (log) => {
      console.log(`New log from ${log.address}`);
    });
    
    // Run for 30 seconds then clean up
    setTimeout(async () => {
      console.log('\nCleaning up subscriptions...');
      
      // Unsubscribe from blocks
      const blockResult = await manager.unsubscribe(blockSubId);
      console.log(`Block unsubscribe result: ${blockResult}`);
      
      // Unsubscribe from logs
      const logResult = await manager.unsubscribe(logSubId);
      console.log(`Log unsubscribe result: ${logResult}`);
      
      // Disconnect
      await manager.disconnect();
      process.exit(0);
    }, 30000);
    
  } catch (error) {
    console.error('Error:', error);
  }
}

main();
```

### Python implementation with context manager

```python theme={"system"}
import json
import asyncio
import websockets
from typing import Dict, Any, Optional
from contextlib import asynccontextmanager

class SubscriptionManager:
    def __init__(self, ws_url: str):
        self.ws_url = ws_url
        self.websocket = None
        self.subscriptions: Dict[str, Any] = {}
        self.request_id = 0
        self.pending_requests = {}
        
    async def connect(self):
        self.websocket = await websockets.connect(self.ws_url)
        print("Connected to Hyperliquid EVM WebSocket")
        
    async def disconnect(self):
        if self.websocket:
            await self.websocket.close()
            print("Disconnected from WebSocket")
    
    async def subscribe(self, subscription_type: str, params: Optional[Dict] = None) -> str:
        self.request_id += 1
        request = {
            "id": self.request_id,
            "jsonrpc": "2.0",
            "method": "eth_subscribe",
            "params": [subscription_type] + ([params] if params else [])
        }
        
        # Create a future to wait for response
        future = asyncio.Future()
        self.pending_requests[self.request_id] = future
        
        await self.websocket.send(json.dumps(request))
        print(f"Subscribing to {subscription_type}...")
        
        # Wait for subscription ID
        subscription_id = await future
        self.subscriptions[subscription_id] = {
            "type": subscription_type,
            "params": params
        }
        print(f"Subscribed with ID: {subscription_id}")
        return subscription_id
    
    async def unsubscribe(self, subscription_id: str) -> bool:
        self.request_id += 1
        request = {
            "id": self.request_id,
            "jsonrpc": "2.0",
            "method": "eth_unsubscribe",
            "params": [subscription_id]
        }
        
        # Create a future to wait for response
        future = asyncio.Future()
        self.pending_requests[self.request_id] = future
        
        await self.websocket.send(json.dumps(request))
        print(f"Unsubscribing from {subscription_id}...")
        
        # Wait for unsubscribe result
        result = await future
        
        if result:
            del self.subscriptions[subscription_id]
            print(f"Successfully unsubscribed from {subscription_id}")
        else:
            print(f"Failed to unsubscribe from {subscription_id}")
        
        return result
    
    async def listen(self, handler):
        """Listen for messages and handle them"""
        async for message in self.websocket:
            data = json.loads(message)
            
            # Handle subscription/unsubscription responses
            if "id" in data:
                request_id = data["id"]
                if request_id in self.pending_requests:
                    self.pending_requests[request_id].set_result(data.get("result"))
                    del self.pending_requests[request_id]
            
            # Handle subscription notifications
            elif data.get("method") == "eth_subscription":
                subscription_id = data["params"]["subscription"]
                if subscription_id in self.subscriptions:
                    await handler(subscription_id, data["params"]["result"])
    
    async def cleanup(self):
        """Unsubscribe from all active subscriptions"""
        print("\nCleaning up subscriptions...")
        for sub_id in list(self.subscriptions.keys()):
            await self.unsubscribe(sub_id)

@asynccontextmanager
async def managed_subscription(ws_url: str):
    """Context manager for automatic subscription cleanup"""
    manager = SubscriptionManager(ws_url)
    try:
        await manager.connect()
        yield manager
    finally:
        await manager.cleanup()
        await manager.disconnect()

# Example usage
async def main():
    ws_url = 'wss://hyperliquid-mainnet.core.chainstack.com/YOUR_ENDPOINT/evm'
    
    async with managed_subscription(ws_url) as manager:
        # Subscribe to different events
        block_sub = await manager.subscribe("newHeads")
        log_sub = await manager.subscribe("logs", {
            "address": "0x5555555555555555555555555555555555555555"
        })
        sync_sub = await manager.subscribe("syncing")
        
        # Handler for notifications
        async def handle_notification(sub_id: str, result: Any):
            if sub_id == block_sub:
                print(f"New block: {int(result['number'], 16)}")
            elif sub_id == log_sub:
                print(f"New log from: {result['address']}")
            elif sub_id == sync_sub:
                if result is False:
                    print("Node is synchronized")
                else:
                    print(f"Syncing: current block {int(result['currentBlock'], 16)}")
        
        # Listen for 30 seconds
        listen_task = asyncio.create_task(manager.listen(handle_notification))
        await asyncio.sleep(30)
        
        # Manual unsubscribe example (optional, cleanup will handle it anyway)
        await manager.unsubscribe(block_sub)
        
        listen_task.cancel()
    
    print("All subscriptions cleaned up automatically")

# Run the example
asyncio.run(main())
```

### Subscription lifecycle management

```javascript theme={"system"}
// Complete subscription lifecycle with error handling
class RobustSubscriptionManager {
  constructor(wsUrl, maxReconnectAttempts = 5) {
    this.wsUrl = wsUrl;
    this.maxReconnectAttempts = maxReconnectAttempts;
    this.reconnectAttempts = 0;
    this.subscriptions = new Map();
    this.handlers = new Map();
  }
  
  async manageSubscription(type, params, duration, handler) {
    console.log(`Starting ${type} subscription for ${duration}ms`);
    
    try {
      // Connect and subscribe
      await this.connect();
      const subId = await this.subscribe(type, params);
      
      // Set up handler
      this.handlers.set(subId, handler);
      
      // Run for specified duration
      await new Promise(resolve => setTimeout(resolve, duration));
      
      // Cleanup
      console.log(`Time's up, unsubscribing from ${type}...`);
      const success = await this.unsubscribe(subId);
      
      if (success) {
        console.log(`✅ Successfully completed ${type} subscription lifecycle`);
      } else {
        console.log(`⚠️ Failed to cleanly unsubscribe from ${type}`);
      }
      
    } catch (error) {
      console.error(`Error in subscription lifecycle: ${error.message}`);
    } finally {
      this.disconnect();
    }
  }
  
  // ... rest of implementation similar to previous example
}

// Example: Monitor blocks for 1 minute
const manager = new RobustSubscriptionManager(CHAINSTACK_WSS_URL);
await manager.manageSubscription(
  'newHeads',
  {},
  60000,  // 1 minute
  (block) => console.log(`Block ${parseInt(block.number, 16)}`)
);
```

## Use cases

The `eth_unsubscribe` method is essential for:

* **Resource management**: Free up server and client resources by canceling unused subscriptions
* **Dynamic subscription control**: Change subscription parameters by unsubscribing and resubscribing
* **Application lifecycle management**: Clean up subscriptions when components unmount or disconnect
* **Rate limiting compliance**: Manage the number of active subscriptions to stay within limits
* **Cost optimization**: Reduce bandwidth and processing costs by removing unnecessary subscriptions
* **Error recovery**: Cancel problematic subscriptions that are causing issues
* **Testing and development**: Clean up test subscriptions during development
* **User preference changes**: Update subscriptions when users change monitoring preferences
* **Performance optimization**: Remove subscriptions that are no longer needed to improve performance
* **Connection management**: Properly clean up before reconnecting or switching endpoints

Proper use of `eth_unsubscribe` ensures efficient resource utilization and clean application shutdown, preventing memory leaks and unnecessary network traffic.
