Documentation Index Fetch the complete documentation index at: https://docs.tagada.io/llms.txt
Use this file to discover all available pages before exploring further.
Path Remapping Guide for React Plugins
Feature Overview Path remapping allows you to customize external URLs while maintaining your plugin’s internal routing logic. Perfect for SEO-optimized URLs, branded paths, and multi-market operations.
Framework React SDK v2 - Requires React with TanStack Query
React is Required : This guide covers path remapping for React-based TagadaPay plugins. All code examples use React hooks and patterns from the TagadaPay SDK v2.
What is Path Remapping?
Path remapping lets you expose custom, SEO-friendly URLs to your users while your plugin continues to use its original internal paths internally.
Example Scenario
Your plugin defines these internal paths:
/checkout
/checkout/step1
/checkout/step2
But you want customers to see:
/buy-now
/buy-now/shipping
/buy-now/payment
Path remapping makes this possible! ✨
SEO Benefits Use keyword-rich URLs like /buy-now instead of /checkout
Brand Consistency Match URLs to your brand language across markets
A/B Testing Test different URL structures without changing plugin code
Multi-Market Localized URLs: /acheter (FR) vs /kaufen (DE) vs /checkout (EN)
How It Works
You configure the mapping in CRM
Tell TagadaPay: “When users visit /custom/:id, route to plugin’s /hello-with-param/:myparam”
TagadaPay injects configuration
The platform automatically injects the mapping as a meta tag in your plugin’s HTML
SDK handles routing
The SDK transparently handles URL matching and parameter extraction
Your plugin works unchanged
Your code continues to use internal paths - no modifications needed!
Architecture
Configuration
In Plugin Manifest
Mark which pages support remapping:
{
"pluginId" : "my-checkout-plugin" ,
"pages" : [
{
"path" : "/" ,
"remappable" : false // Static landing page
},
{
"path" : "/checkout" ,
"remappable" : true // ✅ Can be remapped
},
{
"path" : "/checkout/:step" ,
"remappable" : true // ✅ Can be remapped
},
{
"path" : "/thankyou/:orderId" ,
"remappable" : true // ✅ Can be remapped
}
]
}
In CRM (Done by Merchant)
Merchants configure remapping when mounting your plugin:
// CRM UI allows configuring:
{
from : "/checkout" , // Your plugin's original path
to : "/buy-now" , // Custom external URL
matcher : "^/buy-now.*" // Route matcher pattern
}
SDK Usage
Basic Routing with shouldMatchRoute()
import { shouldMatchRoute } from '@tagadapay/plugin-sdk/v2' ;
import { Route , Routes } from 'react-router-dom' ;
function App () {
return (
< Routes >
< Route path = "/*" element = { < RemappableRoutes /> } />
</ Routes >
);
}
function RemappableRoutes () {
// SDK automatically handles remapping!
if ( shouldMatchRoute ( '/checkout' )) {
return < CheckoutPage /> ;
}
if ( shouldMatchRoute ( '/thankyou/:orderId' )) {
return < ThankYouPage /> ;
}
return < NotFound /> ;
}
What happens:
User visits: /buy-now (external URL)
SDK knows: “This is actually /checkout”
shouldMatchRoute('/checkout') returns true ✅
Your component renders correctly!
New in v2.7.14 : matchRoute() extracts URL parameters from remapped paths automatically!
import { matchRoute } from '@tagadapay/plugin-sdk/v2' ;
function RemappableRoutes () {
const location = useLocation ();
// Check and extract params in one call
const thankYouMatch = matchRoute ( '/thankyou/:orderId' );
if ( thankYouMatch . matched ) {
// ✅ Params are automatically extracted!
return < ThankYouPage orderId = { thankYouMatch . params . orderId } /> ;
}
const checkoutMatch = matchRoute ( '/checkout/:step' );
if ( checkoutMatch . matched ) {
return < CheckoutPage step = { checkoutMatch . params . step } /> ;
}
return < NotFound /> ;
}
Example:
External URL: /order-confirmation/ORD-12345
Internal path: /thankyou/:orderId
Result: { matched: true, params: { orderId: 'ORD-12345' } }
import { getPathInfo } from '@tagadapay/plugin-sdk/v2' ;
function PathDebugger () {
const pathInfo = getPathInfo ();
return (
< div >
< h2 > Path Information </ h2 >
< dl >
< dt > External URL (what user sees): </ dt >
< dd > { pathInfo . externalPath } </ dd >
< dt > Internal Path (plugin's perspective): </ dt >
< dd > { pathInfo . internalPath || 'No remapping' } </ dd >
< dt > Is Remapped: </ dt >
< dd > { pathInfo . isRemapped ? 'Yes' : 'No' } </ dd >
< dt > Query Parameters: </ dt >
< dd > { pathInfo . query . toString () } </ dd >
</ dl >
</ div >
);
}
Real-World Examples
Example 1: E-commerce Checkout
Plugin defines:
/checkout → Main checkout page
/checkout/shipping → Shipping step
/checkout/payment → Payment step
/checkout/confirm → Review step
Merchant wants:
/secure-checkout → Main checkout page
/secure-checkout/delivery → Shipping step
/secure-checkout/pay → Payment step
/secure-checkout/review → Review step
Your plugin code (unchanged!):
function CheckoutRoutes () {
const shippingMatch = matchRoute ( '/checkout/shipping' );
const paymentMatch = matchRoute ( '/checkout/payment' );
const confirmMatch = matchRoute ( '/checkout/confirm' );
if ( shippingMatch . matched ) return < ShippingPage /> ;
if ( paymentMatch . matched ) return < PaymentPage /> ;
if ( confirmMatch . matched ) return < ConfirmPage /> ;
return < CheckoutLandingPage /> ;
}
Result: Works perfectly with both URL structures! ✅
Example 2: Thank You Page with Order ID
Plugin expects:
Merchant wants:
Your plugin code:
function ThankYouRoutes () {
const match = matchRoute ( '/thankyou/:orderId' );
if ( match . matched ) {
// ✅ Works with both /thankyou/123 and /order-complete/123
return < ThankYouPage orderId = { match . params . orderId } /> ;
}
return < NotFound /> ;
}
Example 3: Multi-Market Localization
Plugin internal paths:
/checkout → Universal checkout logic
Different markets:
🇺🇸 English: /checkout
🇫🇷 French: /paiement
🇩🇪 German: /kasse
🇪🇸 Spanish: /comprar
Your plugin:
// Same code works for all markets!
function App () {
if ( shouldMatchRoute ( '/checkout' )) {
return < CheckoutPage /> ;
}
}
Each market configures their preferred external URL in the CRM. Your plugin works everywhere! 🌍
Example 4: Product Pages with Slugs
Plugin:
SEO-Friendly URLs:
/p/amazing-wireless-headphones
/p/ultra-comfy-sneakers
/p/premium-coffee-beans
Implementation:
function ProductRoutes () {
const match = matchRoute ( '/product/:productId' );
if ( match . matched ) {
// ✅ productId = "amazing-wireless-headphones"
return < ProductPage slug = { match . params . productId } /> ;
}
return < ProductGrid /> ;
}
Parameter Name Rules
Important: When remapping paths with parameters, parameter names must match between external and internal paths.
✅ Valid Remapping
{
"from" : "/hello-with-param/:myparam" ,
"to" : "/custom/:myparam"
}
Both use :myparam → Works! ✅
❌ Invalid Remapping
{
"from" : "/hello-with-param/:myparam" ,
"to" : "/custom/:id"
}
Parameter names don’t match → CRM will reject this ❌
Why? This ensures reliable parameter extraction without complex name mapping logic.
Development & Testing
Local Development
Test path remapping in your local environment using localStorage:
// Open browser console and run:
localStorage . setItem ( 'tagadapay-remap' , JSON . stringify ({
externalPath: '/custom/:myparam' ,
internalPath: '/hello-with-param/:myparam'
}));
// Then visit: http://localhost:5173/custom/test123
// Your plugin receives it as: /hello-with-param/test123
Clear remapping:
localStorage . removeItem ( 'tagadapay-remap' );
Query Parameter Method
Alternative testing method:
http://localhost:5173/hello-with-param/123?__remap=/my-custom-path/123
Debugging
Add a debug component to see what’s happening:
import { getPathInfo , matchRoute } from '@tagadapay/plugin-sdk/v2' ;
function PathRemapDebugger () {
const pathInfo = getPathInfo ();
const match = matchRoute ( '/your-internal-path/:param' );
return (
< div className = "debug-panel" >
< h3 > 🔍 Path Remap Debug Info </ h3 >
< div >
< strong > Current URL: </ strong > { window . location . pathname }
</ div >
< div >
< strong > Is Remapped: </ strong > { pathInfo . isRemapped ? '✅ Yes' : '❌ No' }
</ div >
{ pathInfo . isRemapped && (
<>
< div >
< strong > External Path: </ strong > { pathInfo . externalPath }
</ div >
< div >
< strong > Internal Path: </ strong > { pathInfo . internalPath }
</ div >
</>
) }
< div >
< strong > Route Match: </ strong > { match . matched ? '✅ Matched' : '❌ No match' }
</ div >
{ match . matched && match . params && (
< div >
< strong > Extracted Params: </ strong >
< pre > { JSON . stringify ( match . params , null , 2 ) } </ pre >
</ div >
) }
</ div >
);
}
Production Behavior
In production, TagadaPay automatically injects remapping configuration:
< head >
< meta name = "tagadapay-path-remap"
content = "%7B%22external%22%3A%22%2Fcustom%2F%3Amyparam%22%2C%22internal%22%3A%22%2Fhello-with-param%2F%3Amyparam%22%7D" >
</ head >
Decoded:
{
"external" : "/custom/:myparam" ,
"internal" : "/hello-with-param/:myparam"
}
The SDK reads this automatically - no action needed from you!
CDN Distribution
Remapped plugins are served from CDN subdomains:
Original: https://store-123.cdn.tagadapay.com/checkout
Remapped: https://store-123.cdn.tagadapay.com/buy-now
(Both serve the same plugin, SDK handles the routing)
Best Practices
1. Always Use SDK Functions
Don’t parse window.location manually! Always use SDK functions for path matching.
❌ Don’t do this:
// This won't work with remapping!
function CheckoutPage () {
const isCheckout = window . location . pathname === '/checkout' ;
// ...
}
✅ Do this:
// This works with remapping!
function CheckoutPage () {
const isCheckout = shouldMatchRoute ( '/checkout' );
// ...
}
2. Mark Pages as Remappable
In your plugin.manifest.json:
{
"pages" : [
{
"path" : "/admin-panel" ,
"remappable" : false // Internal tool, no need for remapping
},
{
"path" : "/checkout" ,
"remappable" : true // Customer-facing, allow remapping
}
]
}
3. Keep Internal Paths Descriptive
Even if merchants remap them, keep your internal paths clear:
Good:
/checkout
/checkout/shipping
/product/:productId
/thankyou/:orderId
Avoid:
4. Handle Both Scenarios
Your plugin should work whether remapping is active or not:
function App () {
// Works with:
// - /checkout (no remapping)
// - /buy-now (remapped to /checkout)
// - /secure-payment (remapped to /checkout)
if ( shouldMatchRoute ( '/checkout' )) {
return < CheckoutPage /> ;
}
return < HomePage /> ;
}
5. Test Both Paths
During development, test your plugin with:
Original paths : http://localhost:5173/checkout
Remapped paths : Use localStorage to simulate remapping
API Reference
shouldMatchRoute(internalPath: string): boolean
Check if the current URL matches the given internal path.
Parameters:
internalPath: Your plugin’s internal path pattern (e.g., /checkout, /product/:id)
Returns:
boolean: true if current URL matches (considering remapping), false otherwise
Example:
if ( shouldMatchRoute ( '/checkout/:step' )) {
return < CheckoutPage /> ;
}
matchRoute(internalPath: string): RouteMatchResult
Check if route matches AND extract URL parameters.
Parameters:
internalPath: Your plugin’s internal path pattern
Returns:
{
matched : boolean ;
params : Record < string , string > ;
}
Example:
const result = matchRoute ( '/product/:productId' );
// result.matched = true
// result.params = { productId: 'wireless-headphones' }
if ( result . matched ) {
return < ProductPage productId = { result . params . productId } /> ;
}
getPathInfo(): PathInfo
Get detailed information about the current path and remapping status.
Returns:
{
externalPath : string ; // URL user sees
internalPath : string | null ; // Your plugin's path (if remapped)
isRemapped : boolean ; // Whether remapping is active
query : URLSearchParams ; // Query parameters
hash : string ; // URL hash
}
Example:
const info = getPathInfo ();
if ( info . isRemapped ) {
console . log ( `User sees: ${ info . externalPath } ` );
console . log ( `Plugin receives: ${ info . internalPath } ` );
}
getInternalPath(): string | null
Get the current internal path (or null if no remapping).
Returns:
string: Internal path if remapping is active
null: If no remapping is active
Example:
const internalPath = getInternalPath ();
if ( internalPath ) {
console . log ( 'Remapping active! Internal path:' , internalPath );
} else {
console . log ( 'No remapping - using original paths' );
}
Troubleshooting
Parameters are empty
Problem: matchRoute() returns { matched: true, params: {} }
Solution: Ensure parameter names match in your manifest and CRM configuration:
// ✅ Correct
{
"from" : "/product/:productId" ,
"to" : "/p/:productId"
}
// ❌ Wrong
{
"from" : "/product/:productId" ,
"to" : "/p/:id" // Different parameter name!
}
Route not matching
Problem: shouldMatchRoute() returns false when it should match
Checklist:
Is the page marked as remappable: true in your manifest?
Is the internal path correct (check with getPathInfo())?
Are you using the SDK function (not window.location)?
Try adding logging: console.log(getPathInfo())
Works locally but not in production
Problem: Remapping works in development but fails on CDN
Solution:
Check that meta tag is injected: View page source and search for tagadapay-path-remap
Rebuild your plugin: pnpm build
Redeploy: npx @tagadapay/plugin-cli deploy
Clear browser cache and CDN cache
Remapping not working locally
Problem: localStorage remapping doesn’t work
Solution:
// 1. Clear any existing config
localStorage . clear ();
// 2. Set new config (ensure it's valid JSON)
localStorage . setItem ( 'tagadapay-remap' , JSON . stringify ({
externalPath: '/your-external/:param' ,
internalPath: '/your-internal/:param'
}));
// 3. Reload the page (hard refresh: Cmd+Shift+R or Ctrl+Shift+R)
Migration Guide
From Manual Routing
Before (manual routing):
function App () {
const location = useLocation ();
// ❌ Doesn't work with remapping
if ( location . pathname === '/checkout' ) {
return < CheckoutPage /> ;
}
}
After (SDK routing):
import { shouldMatchRoute } from '@tagadapay/plugin-sdk/v2' ;
function App () {
// ✅ Works with remapping!
if ( shouldMatchRoute ( '/checkout' )) {
return < CheckoutPage /> ;
}
}
From React Router Params
Before:
import { useParams } from 'react-router-dom' ;
function ProductPage () {
const { productId } = useParams (); // ❌ Might be empty with remapping
return < Product id = { productId } /> ;
}
After:
import { matchRoute } from '@tagadapay/plugin-sdk/v2' ;
function ProductRoutes () {
const match = matchRoute ( '/product/:productId' );
if ( match . matched ) {
// ✅ Always works, even with remapping
return < ProductPage id = { match . params . productId } /> ;
}
return < NotFound /> ;
}
Advanced Patterns
Nested Routes with Remapping
function App () {
const checkoutMatch = matchRoute ( '/checkout/:step' );
if ( checkoutMatch . matched ) {
return < CheckoutFlow step = { checkoutMatch . params . step } /> ;
}
return < HomePage /> ;
}
function CheckoutFlow ({ step } : { step : string }) {
switch ( step ) {
case 'shipping' :
return < ShippingStep /> ;
case 'payment' :
return < PaymentStep /> ;
case 'review' :
return < ReviewStep /> ;
default :
return < CheckoutLanding /> ;
}
}
Conditional Remapping Display
function PathBreadcrumbs () {
const pathInfo = getPathInfo ();
if ( pathInfo . isRemapped ) {
return (
< nav >
< span > You are here: { pathInfo . externalPath } </ span >
< small > (Internal: { pathInfo . internalPath } ) </ small >
</ nav >
);
}
return < nav > { window . location . pathname } </ nav > ;
}
import { Helmet } from 'react-helmet' ;
function CheckoutPage () {
const pathInfo = getPathInfo ();
// Use external path for canonical URL (what user/Google sees)
const canonicalUrl = `https://example.com ${ pathInfo . externalPath } ` ;
return (
<>
< Helmet >
< link rel = "canonical" href = { canonicalUrl } />
< meta property = "og:url" content = { canonicalUrl } />
</ Helmet >
< div > Checkout content... </ div >
</>
);
}
Next Steps
API Reference Complete SDK API documentation
Examples Real-world plugin examples
Best Practices Optimization tips and patterns
Tutorial Build your first plugin
Need Help?