Tenderly Web3 vs Reactive
This guide walks through how to automate smart contract workflows using Tenderly Web3 Actions and Alerts, and compares their off-chain approach to Reactive’s on-chain, event-driven model — helping developers choose the right tool for reliable Web3 automation.

Tenderly is a powerful Web3 development platform that provides tooling and infrastructure for building, monitoring, and automating blockchain applications across Ethereum and other EVM-compatible networks. Among its core capabilities are Alerts and Web3 Actions, which together enable real-time monitoring and automated responses to on-chain events — without deploying or maintaining backend infrastructure.
In this guide, we will walk through how to use Tenderly Alerts and Web3 Actions to automate a smart contract workflow between two contracts: `Origin` and `Destination`. We'll cover both periodic and alert-based triggers, focusing on execution via the Tenderly Dashboard.
Overview of Contracts
Origin.sol
This contract emits an event whenever a message is posted:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract Origin {
event MessagePosted(address sender, string message);
function postMessage(string calldata _message) external {
emit MessagePosted(msg.sender, _message);
}
}
Destination.sol
This contract logs messages along with the original sender’s address:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract Destination {
event MessageLogged(address originSender, string message);
function logMessage(address _originSender, string calldata _message) external {
emit MessageLogged(_originSender, _message);
}
}
Automation Flow
In this setup, we utilize two types of Web3 Actions in Tenderly:
- Periodic Triggered Actions
- Alert Triggered Actions
The workflow operates as follows:
A Periodic Triggered Action is configured to call the `postMessage(string calldata _message)` function at regular intervals — specifically, every 10 minutes. When this function is executed, it emits the `MessagePosted(address sender, string message)` event. This event serves as the basis for an Alert, which is triggered upon detection of the `MessagePosted` event on-chain. The alert, in turn, activates an Alert Triggered Web3 Action.
As a response, the `logMessage(address _originSender, string calldata _message)` function is called on the destination contract. This results in the emission of the `MessageLogged(address originSender, string message)` event.
Step-by-Step Setup
Step 1 – Initial Setup
- Create a Tenderly account and start a new project.
- You’ll receive 35 million Tenderly Units (TUs) valid for 13 days, which are consumed during automation actions.
- From the left-side menu, go to Contracts and add both contracts by supplying Contract address, ABI, and Verified source code
Step 2 – Creating a Periodic Web3 Action
- In the Tenderly Dashboard, navigate to Web3 Actions from the left-side panel and click Add Action.
- Choose Periodic as the trigger type.
- Set the interval as desired (e.g., every 10 minutes).
- Leave the execution type as parallel (this is fixed and cannot be changed).
- Provide a name and description for your Web3 Action. You can also configure a notification destination (such as your email) if you’d like to be alerted after each execution.
- In the Function section, paste the following function:
const actionFn = async (context, periodicEvent) => {
console.log("Periodic event triggered:", periodicEvent);
const ethers = require('ethers');
const originAbi = [{
"inputs": [{ "internalType": "string", "name": "_message", "type": "string" }],
"name": "postMessage",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
}];
const originAddress = "0x770ca579d7975c0096c09f356d89fe9bbe12a3b7";
try {
const gatewayURL = context.gateways.getGateway("sepolia");
const provider = new ethers.providers.JsonRpcProvider(gatewayURL);
const privateKey = await context.secrets.get("WALLET_PRIVATE_KEY");
const wallet = new ethers.Wallet(privateKey, provider);
const originContract = new ethers.Contract(originAddress, originAbi, wallet);
const timestamp = new Date().toISOString();
const message = `Automated message at ${timestamp}`;
const tx = await originContract.postMessage(message);
const receipt = await tx.wait();
await context.storage.putJson("lastPeriodicRun", {
timestamp,
txHash: receipt.transactionHash
});
return `Successfully posted message at ${timestamp}`;
} catch (error) {
console.error("Error posting message:", error);
throw error;
}
};
module.exports = { actionFn };
- Click Create to deploy your Web3 Action. Once created, it will begin executing at the specified interval.
- Finally, go to the Secrets tab under Web3 Actions, create a new secret named `WALLET_PRIVATE_KEY`, and add your private key. This is used to sign and send the transaction from your wallet.
The outcomes should be similar to these:
Step 3 – Creating an Alert-Based Web3 Action
- Go to Web3 Actions > Add Action
- Set trigger type to Alert
- In the Function section, paste the following code:
const actionFn = async (context, alertEvent) => {
const eventLogs = alertEvent.logs;
if (!eventLogs || eventLogs.length === 0) return;
const ethers = require("ethers");
const abiCoder = new ethers.utils.AbiCoder();
try {
const [originSender, message] = abiCoder.decode(["address", "string"], eventLogs[0].data);
const privateKey = await context.secrets.get("WALLET_PRIVATE_KEY");
let gatewayNetwork;
switch (alertEvent.network) {
case "11155111": gatewayNetwork = "sepolia"; break;
case "1": gatewayNetwork = "mainnet"; break;
case "137": gatewayNetwork = "polygon"; break;
default: throw new Error(`Network ${alertEvent.network} not supported`);
}
const provider = new ethers.providers.JsonRpcProvider(context.gateways.getGateway(gatewayNetwork));
const wallet = new ethers.Wallet(privateKey, provider);
const destinationAbi = [{
"inputs": [
{ "internalType": "address", "name": "_originSender", "type": "address" },
{ "internalType": "string", "name": "_message", "type": "string" }
],
"name": "logMessage",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
}];
const destinationAddress = "0xd01b1dc84dcad25a6bcdfe6ff0445a1da5f017b4";
const destinationContract = new ethers.Contract(destinationAddress, destinationAbi, wallet);
const tx = await destinationContract.logMessage(originSender, message);
const receipt = await tx.wait();
await context.storage.putJson("tx-data-now", {
message,
txHash: receipt.transactionHash,
blockNumber: receipt.blockNumber
});
} catch (error) {
console.error("Alert Action Error:", error);
}
};
module.exports = { actionFn };
- The execution type will be automatically set to parallel (this is fixed and can’t be changed).
- Provide a name and description for your Web3 Action. You may also configure a notification destination, such as your email, to receive alerts after each execution.
- Click Create to deploy your Web3 Action. Once created, it will automatically respond to alert triggers based on your alert conditions.
- Navigate to the Alerts section and select this Web3 Action as the destination for the specific alert you want it to respond to.
Step 4 – Creating an Alert
- In the Tenderly Dashboard, navigate to the Alerts section from the left-hand menu and click New Alert.
- Choose the Event Emitted option as the alert type, since we want to listen for a specific smart contract event.
- Under the Target section, select Single Address, as we’ll be monitoring a specific contract—your origin contract.
- Use the dropdown menu to select the contract address and the event you want to track. This list will display the contracts you've already added to your Tenderly project.
- In the Destination section, choose where you want the alert to be sent. You can select an email notifier to receive alerts in your inbox, and also specify the Web3 Action (created in the previous step) as the destination. This ensures the alert not only notifies you but also triggers the associated on-chain logic automatically.
- Click Create to deploy the alert. It will now appear in the Alerts tab and will activate whenever the specified event is emitted by the contract.
The Alerts would be similar to these:
The Alert Action would look like so:
Final Outcomes on Contracts
- Origin
- Destination
Understanding Reactive Contracts
Reactive contracts are purpose-built for real-time, event-driven smart contract automation — especially in cross-chain environments. Rather than relying on periodic checks or off-chain schedulers, Reactive listens to events natively and responds dynamically, enabling deterministic, high-speed workflows across chains.
Reactive is ideal for builders who need on-chain control, cross-chain coordination, and composable logic — all without relying on off-chain infrastructure.
Key capabilities:
- Reactive triggers: On-chain listeners for real-time responses
- Cross-chain execution: Native routing from origin to destination
- Composable architecture: Chain logic without touching base contracts
- Deterministic automation: All logic is verifiable and traceable on-chain
Reactive is ideal for use cases in DeFi automation, DAO coordination, cross-chain messaging, and other mission-critical flows where decentralization, transparency, and trustlessness are key.
Feature Comparison
Feature | Tenderly Web3 Actions | Reactive Contracts |
---|---|---|
Automation Type | Off-chain, event or time-triggered | On-chain, event-triggered |
Cross-Chain Support | ✅ Scriptable via JS across networks | ✅ Native routing between chains |
UI & Dev Experience | ✅ Modern UI, JS/TS code in-browser | ⚠️ Requires deployment and setup |
Infrastructure | Runs off-chain via Tenderly servers | Fully on-chain, no external infra |
Execution Environment | JavaScript / TypeScript | Solidity-native |
Determinism & Traceability | ⚠️ Depends on off-chain execution | ✅ Fully deterministic and verifiable |
Security Model | Requires private key injection | No private key exposure (on-chain) |
Ideal For | Fast automation, logs, integrations | Protocol-native, cross-chain systems |
Recap
Tenderly Web3 Actions offer a developer-friendly way to build smart contract automation using familiar JavaScript or TypeScript. With a polished UI, built-in network support, and off-chain execution, Tenderly is perfect for use cases that benefit from fast iterations, external service integration, or flexible automation triggers. However, as it's off-chain, determinism and trust assumptions rely on Tenderly’s infrastructure and the developer’s secret management.
Reactive Contracts, on the other hand, are optimized for protocol-level, cross-chain automation. Everything happens on-chain — event detection, logic execution, and cross-chain routing — without any reliance on external infrastructure. This makes Reactive ideal for decentralized applications that require guaranteed execution, transparency, and fine-grained control over reactive behavior across chains.
For teams building secure, cross-chain protocols, Reactive provides unmatched composability and determinism. For developers looking to move quickly and automate operational logic without managing infrastructure, Tenderly is a powerful and efficient tool.
About Reactive Network
The Reactive Network, pioneered by PARSIQ, ushers in a new wave of blockchain innovation through its Reactive Smart Contracts (RSCs). These advanced contracts can autonomously execute based on specific on-chain events, eliminating the need for off-chain computation and heralding a seamless cross-chain ecosystem vital for Web3’s growth.
Central to this breakthrough is the Inversion of Control (IoC) framework, which redefines smart contracts and decentralized applications (DApps) by imbuing them with unparalleled autonomy, efficiency, and interactivity. By marrying RSCs with IoC, Reactive Network is setting the stage for a transformative blockchain era, characterized by enhanced interoperability and the robust, user-friendly foundation Web3 demands.
Website | Blog | Twitter | Telegram | Discord | Docs