To integrate Marketo with Lovable, create a Supabase Edge Function that authenticates with the Marketo REST API using OAuth2 client credentials (Client ID and Client Secret). Store your Munchkin ID, Client ID, and Client Secret in Cloud Secrets. The Edge Function fetches an access token, then calls Marketo endpoints for leads, activities, and smart campaigns. Use Munchkin tracking code in your Lovable frontend for behavioral analytics.
Connect Lovable Apps to Marketo for Enterprise Lead Management and Campaign Automation
Marketo Engage is Adobe's enterprise marketing automation platform, used by thousands of B2B organizations for lead lifecycle management, multi-channel campaign execution, and revenue attribution. When you build a Lovable app — a SaaS product, a resource library, a demo request tool — connecting it to Marketo means every user interaction automatically flows into your marketing automation workflows. New signups become Marketo leads, product usage events become activities, and lead scores update in real time based on what users do in your app.
Marketo's REST API covers virtually all platform capabilities: lead database (create, read, update, delete leads), activities (log custom events against leads), programs and smart campaigns (trigger and manage automation), email marketing (send transactional emails, check campaign membership), and revenue cycle analytics. Authentication uses OAuth2 client credentials — your Lovable Edge Function exchanges a Client ID and Secret for a short-lived access token (valid 1 hour), then uses that token for all subsequent API calls.
The integration has two distinct layers. The backend layer uses Edge Functions to handle authenticated Marketo REST API calls: syncing leads, logging activities, checking campaign membership. The frontend layer uses Munchkin.js — Marketo's JavaScript tracking library — embedded directly in your Lovable app's HTML to track page views and clicks, which feed into Marketo's behavioral scoring automatically. Together these two layers give Marketo a complete picture of each lead's interaction with your app.
Integration method
Marketo uses OAuth2 client credentials authentication for its REST API. A Supabase Edge Function stores your Marketo Munchkin ID, Client ID, and Client Secret in Cloud Secrets, obtains a short-lived access token from Marketo's identity endpoint, and proxies all REST API calls server-side. The Lovable frontend embeds Munchkin.js for behavioral tracking and calls Edge Functions for lead data operations.
Prerequisites
- A Lovable project with Lovable Cloud enabled and Supabase Auth active
- A Marketo Engage subscription with admin access to create API roles and LaunchPoint services
- Your Marketo Munchkin ID (found in Admin → Munchkin in the Marketo interface)
- A Marketo API-only role and LaunchPoint service created (covered in Step 1)
- Basic familiarity with Marketo's REST API documentation at developers.marketo.com
Step-by-step guide
Create a Marketo API role and LaunchPoint service
Create a Marketo API role and LaunchPoint service
In Marketo, navigate to Admin → Users & Roles → Roles and create a new role called 'Lovable API'. Grant this role the minimum permissions your integration needs: Read-Write Lead Database for lead sync, Read-Write Activity for logging activities, and Read-Only for Campaigns if you need campaign membership checks. Avoid granting Admin permissions. Next, go to Admin → LaunchPoint and click New Service. Name it 'Lovable Integration', select 'Custom' as the service type, add an API-only user (create a dedicated API user first under Admin → Users & Roles → Users with a non-human email like api-lovable@yourcompany.com), and assign the Lovable API role. After saving the service, click View Details to see the Client ID and Client Secret for this service. Also find your Munchkin ID in Admin → Munchkin — it looks like 'AAA-BBB-CCC'. You will need all three values: Munchkin ID, Client ID, and Client Secret. Using a dedicated API-only user and role is a security best practice — it limits what the Lovable integration can do if credentials are ever compromised.
Pro tip: Marketo's Munchkin ID determines your REST API base URL: https://{munchkin-id}.mktorest.com. The Munchkin ID in the URL is formatted differently (all lowercase, no dashes) — always use the Munchkin.init() format with dashes for the frontend code.
Expected result: You have a Marketo LaunchPoint service with a Client ID and Client Secret, and you know your Munchkin ID. You have a dedicated API-only user with limited role permissions.
Store credentials in Cloud Secrets
Store credentials in Cloud Secrets
In your Lovable project, open the Cloud tab by clicking the plus (+) icon next to the preview. Go to the Secrets section and add three secrets: MARKETO_MUNCHKIN_ID (your Munchkin ID in the format 'AAA-BBB-CCC'), MARKETO_CLIENT_ID (the Client ID from your LaunchPoint service), and MARKETO_CLIENT_SECRET (the Client Secret from your LaunchPoint service). Click Save after each entry. All three values are now encrypted and available only to Edge Functions. The Munchkin ID determines your API base URL. The Client ID and Client Secret are used to obtain OAuth2 access tokens. Access tokens expire after 3,600 seconds (1 hour), so your Edge Function will need to either cache them or re-request them on each invocation. Caching is more efficient — store the token and its expiry in a Supabase table and reuse it until 5 minutes before expiry.
Pro tip: Store the formatted Munchkin ID (AAA-BBB-CCC with dashes) — your Edge Function will convert it to the REST API base URL format automatically.
Expected result: MARKETO_MUNCHKIN_ID, MARKETO_CLIENT_ID, and MARKETO_CLIENT_SECRET all appear in Cloud Secrets with values masked.
Create the Marketo OAuth2 proxy Edge Function
Create the Marketo OAuth2 proxy Edge Function
Build the Edge Function that handles Marketo OAuth2 token acquisition and proxies REST API calls. The function has two phases: authentication (request a token from the Marketo identity endpoint using client credentials) and API proxying (use the token to call any Marketo REST endpoint). The Marketo token endpoint is https://{munchkin-id}.mktorest.com/identity/oauth/token?grant_type=client_credentials&client_id={id}&client_secret={secret}. The response includes access_token and expires_in (seconds until expiry). Cache this token in a Supabase table to avoid re-authenticating on every request. After obtaining a token, the proxy accepts a method (GET/POST), endpoint (the Marketo REST path like /rest/v1/leads.json), and optional request body, then forwards the call with the token in the Authorization header.
Create a Supabase Edge Function at supabase/functions/marketo-proxy/index.ts. It should authenticate with Marketo using OAuth2 client credentials from MARKETO_MUNCHKIN_ID, MARKETO_CLIENT_ID, and MARKETO_CLIENT_SECRET secrets, caching the access token in a Supabase table. Accept POST requests with JSON body: method (GET/POST), endpoint (Marketo REST path), and body (optional). Forward the request to Marketo's REST API base URL with the Bearer token and return the response.
Paste this in Lovable chat
1import { serve } from 'https://deno.land/std@0.168.0/http/server.ts'2import { createClient } from 'https://esm.sh/@supabase/supabase-js@2'34const corsHeaders = {5 'Access-Control-Allow-Origin': '*',6 'Access-Control-Allow-Headers': 'authorization, x-client-info, apikey, content-type',7}89async function getMarketoToken(munchkinId: string, clientId: string, clientSecret: string, supabase: any): Promise<string> {10 // Check cached token11 const { data: cached } = await supabase12 .from('marketo_token_cache')13 .select('access_token, expires_at')14 .eq('munchkin_id', munchkinId)15 .gt('expires_at', new Date(Date.now() + 300000).toISOString()) // 5 min buffer16 .single()1718 if (cached) return cached.access_token1920 // Request new token21 const tokenUrl = `https://${munchkinId}.mktorest.com/identity/oauth/token?grant_type=client_credentials&client_id=${clientId}&client_secret=${clientSecret}`22 const resp = await fetch(tokenUrl)23 const data = await resp.json()2425 if (!data.access_token) throw new Error(`Marketo auth failed: ${JSON.stringify(data)}`)2627 const expiresAt = new Date(Date.now() + data.expires_in * 1000).toISOString()28 await supabase.from('marketo_token_cache').upsert({29 munchkin_id: munchkinId,30 access_token: data.access_token,31 expires_at: expiresAt,32 }, { onConflict: 'munchkin_id' })3334 return data.access_token35}3637serve(async (req) => {38 if (req.method === 'OPTIONS') return new Response('ok', { headers: corsHeaders })3940 try {41 const supabase = createClient(42 Deno.env.get('SUPABASE_URL')!,43 Deno.env.get('SUPABASE_SERVICE_ROLE_KEY')!,44 )4546 const munchkinId = Deno.env.get('MARKETO_MUNCHKIN_ID')!47 const clientId = Deno.env.get('MARKETO_CLIENT_ID')!48 const clientSecret = Deno.env.get('MARKETO_CLIENT_SECRET')!4950 const { method, endpoint, body: requestBody } = await req.json()5152 const token = await getMarketoToken(munchkinId, clientId, clientSecret, supabase)53 const apiBase = `https://${munchkinId}.mktorest.com`5455 const response = await fetch(`${apiBase}${endpoint}`, {56 method: method || 'GET',57 headers: {58 'Authorization': `Bearer ${token}`,59 'Content-Type': 'application/json',60 },61 body: requestBody ? JSON.stringify(requestBody) : undefined,62 })6364 const data = await response.json()65 return new Response(JSON.stringify(data),66 { headers: { ...corsHeaders, 'Content-Type': 'application/json' } })67 } catch (error) {68 return new Response(JSON.stringify({ error: error.message }),69 { status: 500, headers: { ...corsHeaders, 'Content-Type': 'application/json' } })70 }71})Pro tip: Create the marketo_token_cache table in Supabase with columns: munchkin_id (text, primary key), access_token (text), expires_at (timestamptz). This prevents re-authenticating on every API call.
Expected result: The marketo-proxy Edge Function authenticates with Marketo, caches the token, and forwards API requests. Test it by calling it with endpoint '/rest/v1/leads.json?filterType=email&filterValues=test@example.com'.
Add Munchkin tracking to your Lovable frontend
Add Munchkin tracking to your Lovable frontend
Munchkin.js is Marketo's behavioral tracking script. When embedded in your app, it automatically tracks page visits, form submissions, and click activity for known leads (leads who have filled out a Marketo form or whose email has been associated with the Munchkin cookie). Add the Munchkin script to your Lovable app's HTML head. In Lovable, go to the project settings or ask Lovable chat to add the Munchkin initialization code to your app's main layout or index.html file. The script loads from https://munchkin.marketo.net/munchkin.js and is initialized with your Munchkin ID. For known leads (users who are logged into your Lovable app and whose email is known), you can call Munchkin.munchkinFunction('associateLead', {'Email': userEmail}) after initialization to associate behavioral tracking with their Marketo lead record. This enables Marketo's behavioral scoring to update based on what authenticated users do in your app.
Add the Marketo Munchkin tracking script to our app's index.html file. Use Munchkin ID from a VITE_MARKETO_MUNCHKIN_ID environment variable. The script should load asynchronously from https://munchkin.marketo.net/munchkin.js and initialize with Munchkin.init(munchkinId). In our main layout component, if the user is logged in, also call Munchkin.munchkinFunction('associateLead', {Email: user.email}) to link tracking to their lead record.
Paste this in Lovable chat
1// Add to index.html <head> section2// Replace MUNCHKIN-ID with your actual Munchkin ID3<script type="text/javascript">4 (function() {5 var didInit = false;6 function initMunchkin() {7 if(didInit === false) {8 didInit = true;9 Munchkin.init('MUNCHKIN-ID');10 }11 }12 var s = document.createElement('script');13 s.type = 'text/javascript';14 s.async = true;15 s.src = '//munchkin.marketo.net/munchkin.js';16 s.onreadystatechange = function() {17 if (this.readyState == 'complete' || this.readyState == 'loaded') {18 initMunchkin();19 }20 };21 s.onload = initMunchkin;22 document.getElementsByTagName('head')[0].appendChild(s);23 })();24</script>Pro tip: The Munchkin script is loaded asynchronously and should not block your app's render. Only call associateLead after confirming the Munchkin library has fully loaded to avoid 'Munchkin is not defined' errors.
Expected result: The Munchkin tracking script loads on all pages of your Lovable app. Page visits by known leads appear in their Marketo activity logs under the web visits section.
Implement lead sync on user signup
Implement lead sync on user signup
Wire up lead sync so that when a user registers in your Lovable app (via Supabase Auth), their data is automatically synced to Marketo as a lead. Create a Supabase database function or trigger, or more simply, call the marketo-proxy Edge Function from your signup success handler in the frontend. The Marketo endpoint for creating/updating leads is POST /rest/v1/leads.json with a body containing an action ('createOrUpdate') and a lookupField ('email') plus an input array of lead objects. Key fields to include: email (required), firstName, lastName, and any custom fields your Marketo instance uses for lead source tracking. For complex enterprise setups, RapidDev's team can help configure Supabase triggers that automatically sync user records to Marketo without any frontend code changes.
In our Lovable app's signup success callback, after a user registers with Supabase Auth, call our marketo-proxy Edge Function to sync the user to Marketo. POST to the function with endpoint='/rest/v1/leads.json', method='POST', and body containing action='createOrUpdate', lookupField='email', and input array with the user's email, firstName, and lastName. Show a subtle success indicator when the Marketo sync completes.
Paste this in Lovable chat
1// In your signup success handler2const syncToMarketo = async (user: { email: string, firstName: string, lastName: string }) => {3 try {4 const { data, error } = await supabase.functions.invoke('marketo-proxy', {5 body: {6 method: 'POST',7 endpoint: '/rest/v1/leads.json',8 body: {9 action: 'createOrUpdate',10 lookupField: 'email',11 input: [{12 email: user.email,13 firstName: user.firstName,14 lastName: user.lastName,15 leadSource: 'Lovable App Signup',16 }],17 },18 },19 })20 if (error) console.error('Marketo sync failed:', error)21 else console.log('Lead synced to Marketo:', data)22 } catch (e) {23 console.error('Marketo sync error:', e)24 }25}Pro tip: Make Marketo sync non-blocking — use fire-and-forget (no await on the function call from user-facing flows) so a Marketo API delay never slows down your app's signup experience.
Expected result: New user signups in your Lovable app automatically create or update lead records in Marketo with correct field mapping. You can verify by searching for the email in Marketo's Lead Database.
Common use cases
Sync Lovable app signups to Marketo as leads
When a user creates an account in your Lovable app, automatically create or update their lead record in Marketo with their email, name, and app-specific attributes. This triggers Marketo welcome email sequences and lead scoring immediately upon signup.
When a user signs up in our Lovable app, call our marketo-proxy Edge Function to create or update their Marketo lead record with their email, first name, last name, and a custom field for signup_date. Use the syncLead endpoint. Show a success notification in the UI when the sync completes.
Copy this prompt to try it in Lovable
Log custom app activities for lead scoring
Record meaningful in-app actions (feature activations, document downloads, pricing page views) as Marketo custom activities against each lead. These activities increment lead scores in Marketo's behavioral scoring model, triggering sales alerts when leads reach threshold scores.
Create a function that calls our Marketo Edge Function to log a custom activity whenever a user completes a key action in our app (like downloading a report or activating a paid feature). The activity should include the lead email, activity type name, and activity attributes. Use the Activities endpoint to create the activity record in Marketo.
Copy this prompt to try it in Lovable
Gated content with Marketo lead capture
Build a gated resource library in Lovable where downloading content requires submitting a form. The form data syncs to Marketo as a lead, triggers a smart campaign to send the content by email, and unlocks the download in the app UI. This replaces standalone Marketo landing pages with a native app experience.
Create a gated content download page in our Lovable app. When a user submits the form with their email and company name, call our marketo-proxy Edge Function to sync them as a Marketo lead and add them to the smart campaign with ID 1234. After a successful sync, show the download button and allow them to download the resource.
Copy this prompt to try it in Lovable
Troubleshooting
Edge Function returns 'Marketo auth failed: {"error":"access_denied"}' when obtaining token
Cause: The Client ID or Client Secret is incorrect, or the LaunchPoint service associated with the API user has been deactivated in Marketo.
Solution: In Marketo Admin → LaunchPoint, verify the service is still active and click View Details to confirm the Client ID and Client Secret match what is stored in Cloud Secrets. If in doubt, delete the existing LaunchPoint service and create a new one, then update the secrets in Lovable.
Marketo REST API returns error code 601 'Access token invalid' on API calls
Cause: The cached access token has expired and the token cache table still holds the old value, or the expires_at check logic has a timezone mismatch.
Solution: Clear the marketo_token_cache table in Supabase: DELETE FROM marketo_token_cache. The next API call will request a fresh token. Also verify the expires_at comparison in the Edge Function uses the same timezone (UTC) as Supabase timestamps.
1// Force token refresh by deleting cache2await supabase.from('marketo_token_cache').delete().eq('munchkin_id', munchkinId)Lead sync returns success but leads do not appear in Marketo's Lead Database
Cause: The API-only user associated with the LaunchPoint service does not have Write permissions on the Lead Database, or the lookupField is not set correctly.
Solution: In Marketo Admin → Users & Roles → Roles, verify the role assigned to your API user has 'Read-Write Lead Database' permission. Also verify that lookupField is set to 'email' and that the email field in your input array is a valid email format.
Munchkin tracking is not appearing in lead activity in Marketo
Cause: The Munchkin script may not be loading correctly, or the associateLead call is happening before the Munchkin library is fully initialized.
Solution: Open your browser's network tab and look for requests to munchkin.marketo.net to confirm the script loads. Then look for the Munchkin tracking pixel request (a request to a URL containing /trk?) to confirm tracking is firing. If associateLead throws an error, ensure you call it inside a function that waits for the Munchkin.init() callback.
Best practices
- Create a dedicated API-only Marketo user with a custom role limited to only the permissions your integration needs — never use a personal admin account
- Cache the Marketo OAuth2 access token in Supabase with its expiry time — tokens last 1 hour and re-requesting on every call adds unnecessary latency
- Make all Marketo sync calls non-blocking (fire-and-forget) from user-facing flows so Marketo API latency never degrades your app's user experience
- Always use the createOrUpdate action with lookupField=email for lead sync — this idempotently handles both new leads and updates to existing ones
- Add a custom lead source field to all synced leads so marketing can track which Lovable app features drive lead creation
- Use Munchkin's associateLead function for authenticated users to link behavioral web tracking to their lead records for accurate scoring
- Implement retry logic with exponential backoff for Marketo API calls — the API occasionally returns transient 500 errors that resolve on retry
- Test with Marketo's sandbox environment (if available on your plan) before connecting your production Lovable app to production Marketo data
Alternatives
Klaviyo is designed for e-commerce and SMB email marketing with a simpler API, while Marketo is Adobe's enterprise platform designed for B2B lead management, account-based marketing, and complex multi-touch attribution.
HubSpot combines CRM and marketing automation in a more accessible platform, while Marketo is better suited for large enterprises needing advanced lead scoring, revenue attribution, and Salesforce integration.
Pardot (Salesforce Marketing Cloud Account Engagement) is tightly integrated with Salesforce CRM for B2B marketing, while Marketo is Adobe's platform offering deeper marketing automation features independent of a specific CRM.
Frequently asked questions
What is the difference between Marketo's Munchkin tracking and the REST API?
Munchkin.js is a JavaScript tracking library loaded in the browser that passively records page visits, form completions, and link clicks — it feeds Marketo's behavioral scoring automatically. The REST API is for active data operations: creating leads, reading lead records, adding leads to campaigns, and logging custom activities. Most Marketo integrations use both: Munchkin for automatic behavioral tracking and the REST API for explicit data sync operations.
Does Marketo have a free tier or trial for API access?
Marketo does not offer a free tier. It is an enterprise product with pricing typically starting around $1,000/month for smaller instances. Adobe offers a limited free trial. API access is included in all paid Marketo Engage plans. If you are evaluating Marketo for your organization, request a trial through Adobe's sales team.
How do I find my Marketo REST API base URL?
Your Marketo REST API base URL is derived from your Munchkin ID: https://{munchkin-id}.mktorest.com. For example, if your Munchkin ID is ABC-123-XYZ, your API base URL is https://abc-123-xyz.mktorest.com. Note that the Munchkin ID in the API URL uses lowercase letters — always lowercase your Munchkin ID when constructing the API base URL.
Can I trigger a Marketo Smart Campaign from a Lovable app event?
Yes. Use the Marketo REST API endpoint POST /rest/v1/campaigns/{id}/trigger.json to trigger a requestable smart campaign. First, in Marketo, create a smart campaign with 'Campaign is Requested' as the trigger and set the source to 'Web Service API'. Note the campaign ID from the URL. Then call the trigger endpoint via your marketo-proxy Edge Function passing the campaign ID and the lead email in the input array.
Is it safe to call Marketo's REST API from the Lovable frontend directly?
No. Marketo API calls require an OAuth2 access token that must be obtained using your Client ID and Client Secret. Exposing these credentials in frontend code would allow anyone to access and modify your Marketo lead database. Always proxy Marketo REST API calls through a Supabase Edge Function that retrieves credentials from Cloud Secrets.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation