Writing
Building a Merkl Rewards Integration in a Modern Web3 Application
A deep dive into integrating the Merkl protocol into a modern Web3 application using Next.js. Explore API architecture, reward parsing, wallet interactions, Merkle proof claims, and scalable frontend engineering practices.
Blockchain incentive programs have become a core part of the DeFi ecosystem, but integrating reward distribution into an existing application isn't always straightforward. A production-ready implementation needs to display rewards accurately, provide a smooth claiming experience, and fit naturally into the application's existing architecture without introducing unnecessary complexity.
In one of my recent Web3 frontend projects, I implemented a complete integration with the **Merkl** rewards protocol. The goal was to allow users to view and claim their on-chain rewards while keeping the implementation modular, scalable, and easy to maintain.
Rather than replacing an existing rewards system, the integration was designed as an independent module that could coexist with other claim mechanisms and be extended in the future.
---
# What is Merkl?
Merkl is a decentralized rewards distribution protocol used by many DeFi protocols to incentivize on-chain activity.
Instead of storing claimable balances directly inside smart contracts, Merkl periodically computes user rewards and publishes them as a **Merkle Tree**. Users then submit a Merkle proof to the Distributor contract in order to claim their rewards.
Each reward contains several important values:
* **amount** – Total cumulative rewards in the current Merkle tree * **claimed** – Rewards already claimed on-chain * **pending** – Rewards earned but not yet included in a Merkle root * **proofs** – Merkle proofs required for claiming
One of the most important implementation details is understanding the reward calculation.
The actual claimable amount is:
claimable = amount - claimedThe `pending` value represents rewards that have not yet been committed into a Merkle root and therefore cannot be claimed.
This distinction is essential for displaying accurate balances and preventing incorrect claim attempts.
---
# Technology Stack
The integration was built using technologies already present in the application:
* Next.js (App Router) * TypeScript * React * wagmi * viem * RainbowKit * Tailwind CSS
One design goal was to avoid introducing additional dependencies. Everything was implemented using the existing frontend architecture.
---
# High-Level Architecture
The overall flow looks like this:
User Wallet
│
▼
React UI
│
▼
Custom React Hook
│
▼
Next.js API Route
│
▼
Merkl REST API
│
▼
Reward Parsing
│
▼
Claim Transaction
│
▼
Distributor Smart ContractThe architecture intentionally separates responsibilities.
* UI components only display data. * Custom hooks manage state and wallet interactions. * Service functions communicate with external APIs. * Server routes handle communication with external services. * Smart contract interactions remain isolated from presentation logic.
This separation keeps the codebase easier to maintain as the application grows.
---
# Why Use a Server Proxy?
One interesting challenge was that the browser could not directly communicate with the Merkl API because of the application's Content Security Policy (CSP).
Instead of relaxing browser security policies, I implemented a lightweight Next.js API route that acts as a proxy.
The browser communicates only with the application's backend, while the backend securely fetches data from the Merkl API.
This approach provides several advantages:
* Maintains a strict Content Security Policy * Allows future authentication if required * Centralizes API handling * Simplifies frontend logic * Makes rate limiting easier to implement later
---
# Building a Modular Rewards System
One of the primary goals was modularity.
Instead of scattering Merkl-related logic throughout the application, everything was isolated into its own feature module.
A typical structure looks like this:
merkl/
├── constants
├── types
├── service
├── utilities
├── hooks
└── componentsThis organization makes the integration easy to locate, test, extend, or even remove without affecting unrelated reward systems.
---
# Fetching Rewards
The frontend requests rewards through an internal API route.
The server then retrieves reward information from Merkl's public API and filters the response for the appropriate blockchain network and supported reward token.
After parsing the response, the frontend calculates:
* Total rewards * Already claimed rewards * Currently claimable rewards * Pending rewards * Available Merkle proofs
The UI only enables claiming when:
* Claimable balance is greater than zero * Valid Merkle proofs are available
This prevents unnecessary failed transactions and improves the overall user experience.
---
# The On-Chain Claim Flow
The claiming process follows a straightforward sequence:
1. User connects their wallet. 2. Reward data is loaded. 3. User initiates a claim. 4. The application switches to the correct blockchain network if necessary. 5. Merkle proof data is prepared. 6. The Distributor contract is called. 7. The transaction is confirmed. 8. Reward data is refreshed.
An important implementation detail is that the smart contract expects the **cumulative reward amount**, not only the currently claimable difference.
The contract itself calculates how much has already been claimed and transfers only the remaining rewards.
Using the cumulative amount ensures compatibility with the Distributor contract's accounting model.
---
# User Experience Considerations
Good blockchain UX is often more important than the transaction itself.
The interface was designed to clearly communicate every possible reward state, including:
* Wallet not connected * No rewards available * Rewards fully claimed * Pending rewards awaiting the next Merkle root * Rewards available but missing proofs * Transaction pending * Successful claim * User-rejected transaction * Contract execution failure
Rather than displaying generic errors, each state provides context so users understand exactly what is happening.
---
# Challenges During Development
1. Browser Security Restrictions
The browser could not communicate directly with the external rewards API because of Content Security Policy restrictions.
**Solution**
A Next.js API proxy handled all external communication while keeping browser security intact.
---
2. Correct Reward Calculations
Initially, it was tempting to treat all reported rewards as immediately claimable.
However, Merkl distinguishes between cumulative rewards, claimed rewards, and pending rewards.
**Solution**
The application explicitly computes:
claimable = amount - claimedPending rewards are displayed separately and never treated as claimable.
---
3. Cache Refresh After Claim
Immediately after claiming, cached API responses may still show the previous reward state because indexing can take a short time.
**Solution**
After a successful transaction, the application performs a fresh reward fetch using cache bypass logic so users receive updated information as soon as possible.
---
4. Defensive Error Handling
Blockchain applications encounter many edge cases that traditional web applications do not.
Examples include:
* Wallet disconnected * Wrong network * User rejects signature * Missing Merkle proofs * API unavailable * Smart contract reverts
Handling each scenario individually creates a much smoother user experience than relying on generic error messages.
---
# Key Engineering Decisions
Several architectural decisions made the integration easier to maintain:
* Modular feature-based folder structure * Custom React hooks instead of global state management * Server-side API proxy * Minimal smart contract abstraction * Existing Web3 libraries reused instead of adding new dependencies * Strong TypeScript typing across API responses * Clear separation between fetching, parsing, UI rendering, and contract execution
These decisions reduce long-term maintenance costs and make future enhancements significantly easier.
---
# Future Improvements
The current architecture provides a solid foundation while leaving room for additional features, including:
* Multi-token reward support * Campaign-level reward breakdowns * Historical reward analytics * Additional blockchain networks * Enhanced production caching and rate limiting * Expanded reward dashboards and filtering
Because the implementation is modular, these features can be introduced without major architectural changes.
---
# Final Thoughts
Integrating a Web3 rewards protocol involves much more than simply calling a smart contract. A production-ready solution requires careful handling of API responses, blockchain transactions, caching, wallet interactions, security policies, and user experience.
This project reinforced the importance of building integrations that are modular, maintainable, and resilient to real-world edge cases. By keeping responsibilities clearly separated and designing for future extensibility, the resulting implementation is both easier to maintain and ready to evolve alongside the broader Web3 ecosystem.
---
References
* Merkl Developer Documentation: https://developers.merkl.xyz/integrate-merkl/user-rewards * Merkl Chains & Contracts: https://developers.merkl.xyz/resources/chains-and-contracts * Merkl API Documentation: https://api.merkl.xyz/v4