Modular Monitoring with Web3Actions
This guide demonstrates how to build a flexible monitoring system that can track any on-chain event, process transaction data, and deliver real-time notifications through webhooks. By combining powerful trigger criterias of Tenderly’s Alert system with Web3Actions, you’ll create a modular monitoring infrastructure that can adapt to any blockchain monitoring need, from simple event tracking to complex multi-contract interactions.
This guide assumes you have a Tenderly account and basic familiarity with Web3Actions and blockchain events.
Prerequisites
Before starting, ensure you have:
- Node.js ( v20 currently supported as latest version )
- Tenderly CLI installed
- A webhook endpoint for receiving data
- Basic understanding of TypeScript
System Setup
Create Alert
- Alert Type: We’ll set it up as Successful Transaction. You can find detailed steps here

- Alert Target: As a target we’ll use Tag which let us monitor all contracts and wallets labeled with the specific tag. You can check here how to add Tag for contract or wallet.

- Alert Parameter: Choose Tag from the dropdown that holds contracts we want to monitor

- Alert Destination: For now you can setup whatever you want, in the next phase we’ll set up Web3Action to be Destination for this Alert
Install Dependencies
-
Clone the repo. You can find link to the template here
-
Once you’ve cloned the repo, run the following command inside CLI:
cd actions && npm install
Configure Environment Variables
Set up these Secrets in your Tenderly Web3Action:
WEBHOOK_URL = <Your webhook URL>
BEARER = <Your Tenderly API bearer token>
ACCOUNT_SLUG = <Your Tenderly account slug>
PROJECT_SLUG = <Your project slug>
EVENT_NAME = <Name of the event to track>
Configure tenderly.yaml
Your tenderly.yaml
should look like this:
account_id: "<YOUR_ACCOUNT_ID>"
actions:
<YOUR_ACCOUNT_ID>/<PROJECT_SLUG>:
runtime: v2
sources: actions
specs:
example:
description: "Event tracking system"
function: example:modularFn
trigger:
type: alert
alert: { <YOUR_ALERT_ID> }
execution_type: parallel
project_slug: "<PROJECT_SLUG>"
Be sure to replace the placeholders with following values:
YOUR_ACCOUNT_ID
: Your account ID you can get following this guide.PROJECT_SLUG
: Your project slug you can get following this guide.YOUR_ALERT_ID
: The ID of alert you’ve created in the previous step. You can find the ID in the dashboard.

Deploy your Web3 Action
Run the following command to deploy your Web3 Action:
tenderly actions deploy
Core Components
Transaction Processing
The system begins by processing transaction information:
export const modularFn = async (context: Context, transactionEvent: TransactionEvent) => {
const txHash = transactionEvent.hash;
const txNetwork = transactionEvent.network;
const blockHash = transactionEvent.blockHash;
const blockNumber = transactionEvent.blockNumber;
const WEBHOOK_URL = await context.secrets.get("WEBHOOK_URL");
const BEARER = await context.secrets.get("BEARER");
const ACCOUNT_SLUG = await context.secrets.get("ACCOUNT_SLUG");
const PROJECT_SLUG = await context.secrets.get("PROJECT_SLUG");
const EVENT_NAME = await context.secrets.get("EVENT_NAME");
if (!EVENT_NAME) {
throw new Error("EVENT_NAME not found in environment variables");
}
const url = `https://api.tenderly.co/api/v1/public-contract/${txNetwork}/trace/${txHash}`;
const traceResponse = await axios.get(url, {
headers: {
authorization: BEARER,
},
});
const traceData = traceResponse.data;
This component:
- Captures transaction hash and network
- Retrieves transaction traces via Tenderly API
- Processes block information
Contract Information Retrieval
Contract information (names and ABIs) are fetched using the Contracts API.
const fetchContractName = async (addr: string) => {
const contractEndpoint = `https://api.tenderly.co/api/v1/account/${ACCOUNT_SLUG}/project/${PROJECT_SLUG}/contract/${txNetwork}/${addr}`;
try {
const contractResponse = await axios.get(contractEndpoint, {headers: {'Authorization': BEARER}});
return contractResponse.data.contract.contract_name;
} catch (error) {
console.error(`Error fetching contract name from endpoint for ${addr}:`, error);
}
};
const fetchContractAbi = async (addr: string) => {
const contractEndpoint = `https://api.tenderly.co/api/v1/account/${ACCOUNT_SLUG}/project/${PROJECT_SLUG}/contract/${txNetwork}/${addr}`;
try {
const contractResponse = await axios.get(contractEndpoint, {headers: {'Authorization': BEARER}});
return contractResponse.data.contract.data.abi;
} catch (error) {
console.error(`Error fetching contract ABI from endpoint for ${addr}:`, error);
}
};
Event Processing
Event processing is handled through specialized functions:
const extractEventAddresses = (logs: any[]): string[] =>
Array.from(new Set(
logs
.filter(log => log.name === EVENT_NAME)
.map(log => log.raw.address)
));
const extractEventDetails = (logs: any[]) => {
return logs
.filter(log => log.name === EVENT_NAME)
.map(log => {
const result: { [key: string]: string } = {
name: log.name
};
log.inputs.forEach((input: any) => {
const name = input.soltype.name;
const value = input.value.toString();
result[name] = value;
});
return result;
});
};
This section:
- Filters events by name
- Extracts event parameters
- Processes event addresses
Webhook interaction
The system sends this structured data to your webhook using Axios:
{
hash: string, // Transaction hash
transaction: object, // Full transaction event
blockHash: string, // Block hash
blockNumber: number, // Block number
matchReasons: Array<{ // Event details
name: string,
[parameterName: string]: string
}>,
sentinel: { // Contract information
contractName: string,
abi: object
},
traceData: object, // Transaction trace data
addresses: string[] // Involved addresses
}
Troubleshooting
Common issues and solutions:
-
Missing Events
- Verify EVENT_NAME matches contract events exactly
- Check alert configuration in Tenderly dashboard
- Review transaction logs for event emission
-
API Errors
- Validate BEARER token permissions
- Check API endpoint availability
- Verify network configuration
-
Webhook Issues
- Confirm WEBHOOK_URL accessibility
- Check payload format matches expectations
- Monitor webhook endpoint logs