@marvalt/madapter
v2.3.4
Published
MarVAlt adapter for Mautic integration (React + static data generator)
Maintainers
Readme
madapter
A MarVAlt adapter for Mautic marketing automation in React, with static data generation support.
Features
- 🚀 Mautic API Client - Full-featured client for Mautic API operations
- 📝 Dynamic Form Rendering - Render Mautic forms dynamically in React
- 📊 Static Data Generation - Generate static JSON files for build-time data
- 🎯 Event Tracking - Mautic tracking script integration with proxy support
- 🔧 React Hooks - Comprehensive React Query hooks for all Mautic operations
- 🛡️ TypeScript Support - Full TypeScript support with comprehensive type definitions
- 🔐 Authentication Modes - Support for Cloudflare Worker proxy and direct API access
- ✅ Form Validation - Client-side validation with customizable rules
- 🎨 Customizable Components - Flexible and customizable React components
Installation
npm install @marvalt/madapterPeer Dependencies
npm install @tanstack/react-query react react-domQuick Start
1. Environment Configuration
Use the same auth mode variable used by all integrations: VITE_AUTH_MODE.
Create .env (non‑secret):
# Global auth mode used across integrations
VITE_AUTH_MODE=cloudflare_proxy # or direct (dev only)
# Mautic via Cloudflare Worker proxy
VITE_MAUTIC_PROXY_URL=https://your-mautic-proxy.workers.dev
# Frontend app identity used by the Worker for auth headers
VITE_FRONTEND_ID=your-app-id
VITE_FRONTEND_SECRET=your-worker-secret
# Mautic OAuth client credentials (typically configured on the Worker)
# Add here only if your tooling expects them documented in the app env.
VITE_MAUTIC_API_PUBLIC_KEY=your-mautic-api-public-keyCreate .env.local (secrets for local dev only):
# Secret OAuth key (usually a Worker secret, optional in app env)
VITE_MAUTIC_API_SECRET_KEY=your-mautic-api-secret-keyNotes:
- In proxy mode, the Worker reads
MAUTIC_API_PUBLIC_KEYandMAUTIC_API_SECRET_KEYfrom its own environment. - The frontend sends
x-app-idandx-worker-secretheaders; the client sets these automatically.
2. React Query Setup
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
const queryClient = new QueryClient();
function App() {
return (
<QueryClientProvider client={queryClient}>
{/* Your app components */}
</QueryClientProvider>
);
}The client auto‑configures from import.meta.env/process.env. If you prefer explicit configuration, wrap your app with the provider exported by the package and pass the config fields shown above.
3. Form Rendering (recommended)
import { MauticForm } from '@marvalt/madapter';
function ContactPage() {
return (
<div>
<h1>Contact Us</h1>
<MauticForm
formId="1"
title="Get in Touch"
description="Send us a message and we'll get back to you soon."
onSuccess={(data) => console.log('Form submitted:', data)}
onError={(error) => console.error('Form error:', error)}
/>
</div>
);
}4. Event Tracking
import { MauticTracking } from '@marvalt/madapter';
function App() {
return (
<MauticTracking
enabled={true}
proxyUrl={process.env.VITE_MAUTIC_PROXY_URL}
appId={process.env.VITE_FRONTEND_ID}
workerSecret={process.env.VITE_FRONTEND_SECRET}
>
{/* Your app content */}
</MauticTracking>
);
}Static Data Generation
1. Create Generation Script
// scripts/generateMauticData.ts
import { generateMauticData } from '@marvalt/madapter';
async function generateData() {
try {
const staticData = await generateMauticData({
authMode: 'cloudflare_proxy',
cloudflareWorkerUrl: process.env.VITE_MAUTIC_PROXY_URL,
appId: process.env.VITE_FRONTEND_ID,
workerSecret: process.env.VITE_FRONTEND_SECRET,
outputPath: './src/data/mautic-data.json',
includeInactive: false,
});
console.log(`Generated data for ${staticData.total_forms} forms`);
} catch (error) {
console.error('Error generating Mautic data:', error);
process.exit(1);
}
}
generateData();2. Update package.json
{
"scripts": {
"generate:mautic-data": "tsx scripts/generateMauticData.ts",
"build": "npm run generate:mautic-data && vite build"
}
}React Hooks
Form Submission
import { useMauticFormSubmission } from '@marvalt/madapter';
function CustomForm() {
const submitMutation = useMauticFormSubmission();
const handleSubmit = async (formData) => {
try {
await submitMutation.mutateAsync({
formId: 1,
fields: formData,
returnUrl: window.location.href,
});
console.log('Form submitted successfully!');
} catch (error) {
console.error('Form submission failed:', error);
}
};
return (
<form onSubmit={handleSubmit}>
{/* Your form fields */}
</form>
);
}Contact Management
import { useMauticCreateContact, useMauticContactByEmail } from '@marvalt/madapter';
function ContactManager() {
const createMutation = useMauticCreateContact();
const { data: contact } = useMauticContactByEmail('[email protected]');
const handleCreateContact = async (contactData) => {
await createMutation.mutateAsync({
email: contactData.email,
firstname: contactData.firstName,
lastname: contactData.lastName,
});
};
return (
<div>
{contact && <p>Contact found: {contact.data?.firstname}</p>}
{/* Your contact management UI */}
</div>
);
}Event Tracking
import { useMauticEventTracking } from '@marvalt/madapter';
function ProductPage() {
const trackEvent = useMauticEventTracking();
const handleProductView = () => {
trackEvent.mutate({
email: '[email protected]',
eventName: 'product_view',
eventData: { productId: '123', category: 'electronics' },
});
};
return (
<div>
<button onClick={handleProductView}>Track Product View</button>
</div>
);
}API Reference
MauticClient
import { MauticClient } from '@marvalt/madapter';
const client = new MauticClient({
authMode: 'cloudflare_proxy',
cloudflareWorkerUrl: 'https://proxy.workers.dev',
appId: 'your-app-id',
workerSecret: 'your-secret',
});
// Form operations
await client.submitForm(1, { formId: 1, fields: { email: '[email protected]' } });
await client.getForms();
await client.getForm(1);
// Contact operations
await client.createContact({ email: '[email protected]', firstname: 'Test' });
await client.updateContact(1, { firstname: 'Updated' });
await client.getContactByEmail('[email protected]');
// Event tracking
await client.trackEvent('page_view', { page: '/home' });
// Tag management
await client.addTagToContact(1, ['newsletter', 'premium']);
await client.removeTagFromContact(1, ['newsletter']);Configuration
interface MauticConfig {
authMode: 'cloudflare_proxy' | 'direct';
apiUrl?: string; // Required for direct mode
cloudflareWorkerUrl?: string; // Required for proxy mode
appId?: string; // Required for proxy mode
workerSecret?: string; // Required for proxy mode
timeout?: number; // Default: 30000ms
retries?: number; // Default: 3
}Authentication Modes
Cloudflare Worker Proxy (Recommended)
const config = {
authMode: 'cloudflare_proxy',
cloudflareWorkerUrl: 'https://your-proxy.workers.dev',
appId: 'your-frontend-id',
workerSecret: 'your-worker-secret',
};Direct API Access (Legacy)
const config = {
authMode: 'direct',
apiUrl: 'https://your-mautic-instance.com',
};Form Field Types
The package supports all standard Mautic field types:
text- Text inputemail- Email input with validationtel- Phone number inputurl- URL inputtextarea- Multi-line text inputselect- Dropdown selectioncheckbox- Single checkboxradio- Radio button group
Customization
Custom Form Styling
<MauticForm
formId="1"
className="custom-form"
// Custom CSS classes will be applied to form elements
/>Custom Validation
import { validateField } from '@marvalt/madapter';
const customValidation = (field, value) => {
const baseError = validateField(field, value);
if (baseError) return baseError;
// Add custom validation logic
if (field.alias === 'custom_field' && value.length < 5) {
return 'Custom field must be at least 5 characters';
}
return null;
};Error Handling & Common Pitfalls
import { MauticForm } from '@marvalt/madapter';
function FormWithErrorHandling() {
const handleError = (error) => {
console.error('Form submission error:', error);
// Custom error handling logic
};
return (
<MauticForm
formId="1"
onError={handleError}
onSuccess={(data) => console.log('Success:', data)}
/>
);
}Tips to avoid errors:
- 404/HTML after submit: Some Mautic setups return an HTML page (even 404) after a successful submit. The client treats this as success. If you implement custom submission, do not rely on server redirects; handle redirects client‑side using the form’s configured
postAction. - Redirects: Prefer client‑side redirects. The client sets
mauticform[return]to an empty string and performs the redirect on the frontend. - Dev tracking: Tracking is disabled in
VITE_DEV/development builds by design; don’t expectmtc.jsto load locally. - Proxy headers: In proxy mode the client sends
x-app-idandx-worker-secretautomatically. EnsureVITE_FRONTEND_IDandVITE_FRONTEND_SECRETare set. - Forms data: If you reference a form ID that doesn’t exist in your Mautic instance, you’ll receive a 404 from the API. Use the static data generator or fetch
/formsvia the Worker to confirm IDs.
Development
Building the Package
npm run buildRunning Tests
npm test
npm run test:watch
npm run test:coverageLinting
npm run lint
npm run lint:fixLicense
GPL-3.0-or-later. See LICENSE.
Support
For support and questions, please contact:
- Email: [email protected]
- Documentation: GitHub Repository
Changelog
1.0.0
- Initial release
- Mautic API client
- React components and hooks
- Static data generation
- Event tracking
- TypeScript support
