MarVAlt adapter for Mautic integration (React + static data generator)
npm install @marvalt/madapterA MarVAlt adapter for Mautic marketing automation in React, with static data generation support.
- 🚀 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
``bash`
npm install @marvalt/madapter
`bash`
npm install @tanstack/react-query react react-dom
Use the same auth mode variable used by all integrations: VITE_AUTH_MODE.
Create .env (non‑secret):`bashGlobal auth mode used across integrations
VITE_AUTH_MODE=cloudflare_proxy # or direct (dev only)
Create
.env.local (secrets for local dev only):
`bash
Secret OAuth key (usually a Worker secret, optional in app env)
VITE_MAUTIC_API_SECRET_KEY=your-mautic-api-secret-key
`Notes:
- In proxy mode, the Worker reads
MAUTIC_API_PUBLIC_KEY and MAUTIC_API_SECRET_KEY from its own environment.
- The frontend sends x-app-id and x-worker-secret headers; the client sets these automatically.$3
`tsx
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';const queryClient = new QueryClient();
function App() {
return (
{/ Your app components /}
);
}
`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
`tsx
import { MauticForm } from '@marvalt/madapter';function ContactPage() {
return (
Contact Us
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)}
/>
);
}
`$3
`tsx
import { MauticTracking } from '@marvalt/madapter';function App() {
return (
enabled={true}
proxyUrl={process.env.VITE_MAUTIC_PROXY_URL}
appId={process.env.VITE_FRONTEND_ID}
workerSecret={process.env.VITE_FRONTEND_SECRET}
>
{/ Your app content /}
);
}
`Static Data Generation
$3
`typescript
// 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();
`$3
`json
{
"scripts": {
"generate:mautic-data": "tsx scripts/generateMauticData.ts",
"build": "npm run generate:mautic-data && vite build"
}
}
`React Hooks
$3
`tsx
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 (
);
}
`$3
`tsx
import { useMauticCreateContact, useMauticContactByEmail } from '@marvalt/madapter';function ContactManager() {
const createMutation = useMauticCreateContact();
const { data: contact } = useMauticContactByEmail('user@example.com');
const handleCreateContact = async (contactData) => {
await createMutation.mutateAsync({
email: contactData.email,
firstname: contactData.firstName,
lastname: contactData.lastName,
});
};
return (
{contact && Contact found: {contact.data?.firstname}
}
{/ Your contact management UI /}
);
}
`$3
`tsx
import { useMauticEventTracking } from '@marvalt/madapter';function ProductPage() {
const trackEvent = useMauticEventTracking();
const handleProductView = () => {
trackEvent.mutate({
email: 'user@example.com',
eventName: 'product_view',
eventData: { productId: '123', category: 'electronics' },
});
};
return (
);
}
`API Reference
$3
`typescript
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: 'test@example.com' } });
await client.getForms();
await client.getForm(1);
// Contact operations
await client.createContact({ email: 'test@example.com', firstname: 'Test' });
await client.updateContact(1, { firstname: 'Updated' });
await client.getContactByEmail('test@example.com');
// Event tracking
await client.trackEvent('page_view', { page: '/home' });
// Tag management
await client.addTagToContact(1, ['newsletter', 'premium']);
await client.removeTagFromContact(1, ['newsletter']);
`$3
`typescript
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
$3
`typescript
const config = {
authMode: 'cloudflare_proxy',
cloudflareWorkerUrl: 'https://your-proxy.workers.dev',
appId: 'your-frontend-id',
workerSecret: 'your-worker-secret',
};
`$3
`typescript
const config = {
authMode: 'direct',
apiUrl: 'https://your-mautic-instance.com',
};
`Form Field Types
The package supports all standard Mautic field types:
-
text - Text input
- email - Email input with validation
- tel - Phone number input
- url - URL input
- textarea - Multi-line text input
- select - Dropdown selection
- checkbox - Single checkbox
- radio - Radio button groupCustomization
$3
`tsx
formId="1"
className="custom-form"
// Custom CSS classes will be applied to form elements
/>
`$3
`typescript
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
`tsx
import { MauticForm } from '@marvalt/madapter';function FormWithErrorHandling() {
const handleError = (error) => {
console.error('Form submission error:', error);
// Custom error handling logic
};
return (
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 expect mtc.js to load locally.
- Proxy headers: In proxy mode the client sends x-app-id and x-worker-secret automatically. Ensure VITE_FRONTEND_ID and VITE_FRONTEND_SECRET are 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 /forms via the Worker to confirm IDs.Development
$3
`bash
npm run build
`$3
`bash
npm test
npm run test:watch
npm run test:coverage
`$3
`bash
npm run lint
npm run lint:fix
``GPL-3.0-or-later. See LICENSE.
For support and questions, please contact:
- Email: support@vibune.com
- Documentation: GitHub Repository