# Moz

- Tool: Bubble
- Difficulty: Intermediate
- Time required: 2–3 hours
- Last updated: July 2026

## TL;DR

Connect Bubble to Moz's Links API v2 using the API Connector plugin with HTTP Basic Auth — manually base64-encode your Access ID and Secret Key before placing them in a Private Authorization header. Bubble proxies all calls server-side so credentials stay hidden. The primary use case is a link-building CRM: batch up to 50 domains per POST /url_metrics call, store DA and PA scores in a Domain_Authority Data Type, and display sortable results in a Repeating Group. Requires Moz Pro Standard (~$99/mo).

## Build a link-building CRM with Moz Domain Authority data inside Bubble

Domain Authority and Page Authority are among the most widely used metrics in SEO — and Moz is the authoritative source for both. The Moz Links API v2 is one of the few SEO data APIs that provides real link authority metrics programmatically, making it a powerful addition to any Bubble SEO tool or link-building CRM.

The highest-value use case for this integration is a link prospect tracker: paste a list of competitor or prospect domains into your Bubble app, trigger a batch POST /url_metrics call, store the returned DA and PA scores, and surface a sortable Repeating Group so your outreach team can prioritize high-DA domains without logging in to Moz Pro.

Before diving into the technical setup, there are two things to resolve. First: Moz Pro Standard plan (~$99/mo) or higher is required for API access — no API key is available on free Moz accounts. Second: Bubble's API Connector does not have a native Basic Auth option, so you need to manually base64-encode your Access ID and Secret Key using your browser console. This is a five-second step but it catches many builders off-guard. This page walks through it in detail.

This is the highest-opportunity integration in the Bubble SEO toolset — 6,985 monthly impressions from people searching for exactly this setup.

## Before you start

- A Moz Pro subscription at Standard tier or higher (~$99/mo) — no API access is available on free Moz accounts
- Your Moz Access ID and Secret Key from moz.com/products/pro/api (available after logging in with a Pro subscription)
- A Bubble account with the API Connector plugin installed (free, by Bubble)
- For batch processing more than 50 domains or for scheduled DA refreshes: a paid Bubble plan (Starter $32/mo+) for Backend Workflows

## Step-by-step guide

### 1. Get your Moz API credentials and compute the Basic Auth string

Log in to moz.com and navigate to moz.com/products/pro/api (or find the API section under your account dashboard). You will see two credentials:
- Access ID: a string that looks like mozscape-xxxxxxxxxxxxxxxx
- Secret Key: a longer alphanumeric string

Copy both. Now you need to compute the Basic Auth string that goes into Bubble's API Connector. HTTP Basic Auth encodes the credentials as base64(AccessID:SecretKey). Here is how to do this in 10 seconds:

1. Open any webpage in your browser (even a blank tab).
2. Press F12 to open Developer Tools.
3. Click the Console tab.
4. Type the following, replacing with your actual credentials:
   btoa('YOUR_ACCESS_ID:YOUR_SECRET_KEY')
5. Press Enter. The console returns a base64-encoded string like: bW96c2NhcGUteHh4Onl5eXl5
6. The complete Authorization header value you will use is: Basic bW96c2NhcGUteHh4Onl5eXl5

Store this base64 string (not the raw credentials) — it is what you will paste into Bubble. This is a one-time computation. If you regenerate your Moz credentials, you will need to recompute the base64 string.

Important: the colon between Access ID and Secret Key in the btoa() call is required. Omitting it or reversing the order will produce a different base64 string that will not authenticate with Moz's API.

```
// Run this in your browser console (F12 → Console tab)
// Replace with your actual Moz credentials
btoa('mozscape-xxxxxxxxxxxxxxxx:your-secret-key-here')

// Output example: 'bW96c2NhcGUteHh4eHh4eHh4eHh4OnNlY3JldGtleQ=='

// Full Authorization header value:
// Basic bW96c2NhcGUteHh4eHh4eHh4eHh4OnNlY3JldGtleQ==

// Format: 'Basic ' + btoa('ACCESS_ID:SECRET_KEY')
// The word 'Basic' followed by a space is REQUIRED
```

**Expected result:** You have a base64 string computed from your Access ID and Secret Key, and you have formatted it as 'Basic [base64string]' ready to paste into Bubble's API Connector.

### 2. Configure the API Connector with Basic Auth

In your Bubble app editor, click the Plugins tab in the left sidebar. Click 'Add plugins', search for 'API Connector' (the free official plugin by Bubble), and install it. After installation, click the API Connector in your plugins list to open it, then click 'Add another API'. Name this API 'Moz API'.

Set the Base URL to: https://lsapi.seomoz.com/v2

Click 'Add a shared header'. In the Key field, enter: Authorization. In the Value field, paste your precomputed string in the format 'Basic [your-base64-string]' — for example: Basic bW96c2NhcGUteHh4eHh4eHh4eHh4OnNlY3JldGtleQ==

Check the 'Private' checkbox next to this header. This is the critical step — the Private checkbox ensures Bubble stores this header on its servers and never sends it to the browser. Even though the credentials are already base64-encoded (not encrypted), marking them Private prevents exposure in browser network logs or page source.

Also add a Content-Type shared header: Key = Content-Type, Value = application/json, Private = unchecked. The Moz API requires this for POST requests.

Do not add any other credentials to individual calls — the shared Authorization header covers all calls made under this API entry.

```
{
  "api_name": "Moz API",
  "base_url": "https://lsapi.seomoz.com/v2",
  "shared_headers": [
    {
      "key": "Authorization",
      "value": "Basic YOUR_BASE64_ENCODED_CREDENTIALS",
      "private": true
    },
    {
      "key": "Content-Type",
      "value": "application/json",
      "private": false
    }
  ]
}
```

**Expected result:** The API Connector lists 'Moz API' with a Private Authorization header (Basic + base64 string) and a Content-Type: application/json header. No individual calls have been added yet.

### 3. Add the POST /url_metrics batch call

The primary Moz Links API endpoint for this integration is POST /url_metrics, which accepts a JSON body containing an array of up to 50 target URLs and returns DA, PA, Spam Score, and link count data for each.

In the API Connector under your Moz API entry, click 'Add another call'. Name it 'batch_url_metrics'. Set the method to POST. In the URL path field, enter: /url_metrics (this appends to the base URL to form https://lsapi.seomoz.com/v2/url_metrics).

In the Body section, set the content type to 'JSON' and enter the request body structure:
{"targets": ["[domain]"]}

The [domain] parameter should be set as a dynamic value. Add a parameter named 'targets' as a JSON array body parameter. Since this is a batch endpoint that takes multiple domains, you will pass the array programmatically from your Bubble Workflow — but for initialization purposes, use a test value like {"targets": ["moz.com", "example.com"]}.

Set 'Use as' to Action — even though this call returns data, it is a POST request. Bubble treats it as an Action, and you can still read the result object in workflow steps.

Click 'Initialize call'. If the Authorization header is correctly configured, Moz will return DA, PA, and metrics for the test domains. Bubble will auto-detect the response fields. Verify that the response shows a 'results' array with items containing: domain_authority, page_authority, spam_score, root_domains_to_root_domain, and external_equity_links fields.

```
POST https://lsapi.seomoz.com/v2/url_metrics

Headers:
  Authorization: Basic <private>
  Content-Type: application/json

Body:
{
  "targets": [
    "moz.com",
    "example.com"
  ]
}

Response shape:
{
  "results": [
    {
      "page": "moz.com",
      "domain_authority": 91,
      "page_authority": 71,
      "spam_score": 2,
      "root_domains_to_root_domain": 42318,
      "external_equity_links": 1054321
    }
  ]
}
```

**Expected result:** The batch_url_metrics call is initialized and shows green status. Detected fields include domain_authority (number), page_authority (number), spam_score (number), root_domains_to_root_domain (number), and external_equity_links (number) inside a results array.

### 4. Create the Domain_Authority Data Type for caching

Moz API credits are consumed per URL in a batch — 50 URLs in one POST request = 50 credits against your monthly plan limit. Moz updates DA scores on a monthly cycle, so there is no benefit to calling the API more often than that for the same domain. Store results in a Bubble Data Type and check the cache before making API calls.

Go to the Data tab in your Bubble editor. Click 'New type' and name it 'Domain_Authority'. Add these fields by clicking 'Create a new field' for each:
- domain: Text (the domain URL, e.g., 'competitor.com')
- da: Number (domain_authority from API)
- pa: Number (page_authority from API)
- spam_score: Number
- root_domains: Number (root_domains_to_root_domain)
- equity_links: Number (external_equity_links)
- fetched_date: Date (when this record was last updated from the Moz API)

Go to Data tab → Privacy for the Domain_Authority Data Type. Set privacy rules so that 'Everyone else' cannot read or search these records — your DA data is business-sensitive information about your competitors. Enable access only for appropriate user roles in your app.

The domain field should be treated as a unique identifier. Before creating a new Domain_Authority record, always search for an existing one with the same domain value and update it rather than creating a duplicate.

```
Data Type: Domain_Authority
Fields:
  - domain: Text (the domain name, e.g., competitor.com)
  - da: Number (Moz domain_authority score, 0-100)
  - pa: Number (Moz page_authority score, 0-100)
  - spam_score: Number (0-100; higher = more spammy)
  - root_domains: Number (unique root domains linking in)
  - equity_links: Number (total external equity links)
  - fetched_date: Date (when last synced from Moz)

Privacy rules:
  Everyone else → Find in searches: No
  Everyone else → Read: No
  Admin role → All permissions: Yes
```

**Expected result:** The Domain_Authority Data Type appears in the Data tab with all seven fields and privacy rules restricting access to authorized users only.

### 5. Build the batch DA lookup workflow

The batch lookup workflow takes a list of domain names, checks the cache for each, collects the ones that need refreshing, sends them to Moz in batches of 50, and stores the results. Here is the architecture:

In your Bubble app, create a page with a Multi-line Input for domain names (one per line) and a 'Get DA Scores' button.

Workflow: 'Get DA Scores' button is clicked
Step 1: Split the Multi-line Input's value into a list by line break. In Bubble, use ':split by' operator with the newline character. Store this as a Custom State (type: list of text) named 'domain_list'.
Step 2: For each domain in domain_list, check if a fresh Domain_Authority record exists (fetched_date > Current date/time minus 30 days). Collect only the domains that need a fresh score.
Step 3: Call batch_url_metrics with the domains that need refreshing. Since the POST body requires a JSON array, and Bubble's API Connector expects the body as a text field, format the list as a JSON string: '["domain1.com","domain2.com"]'.
Step 4: For each result in the API response's results array, create or update a Domain_Authority record: domain = result's page, da = result's domain_authority, pa = result's page_authority, spam_score = result's spam_score, fetched_date = Current date/time.

Batch size limitation: the Moz API accepts a maximum of 50 URLs per POST request. For lists longer than 50 domains, implement a recursive Backend Workflow that processes 50 domains at a time. RapidDev's team has built this exact batching pattern for Bubble SEO tools — if you need help architecting the recursive loop for large domain lists, reach out at rapidevelopers.com/contact.

```
Workflow: 'Get DA Scores' button clicked

Step 1: Set Custom State 'domain_list' = MultilineInput's value :split by '\n' :filter where not empty

Step 2: Identify stale domains:
  For each domain in domain_list:
    If Search Domain_Authority where domain=current item AND fetched_date > current date-30days, count = 0
    → add to 'needs_refresh' custom state (list of text)

Step 3 [Only when needs_refresh count > 0]:
  Call API → Moz API - batch_url_metrics
  Body: {"targets": [needs_refresh as JSON array]}
  Result name: moz_results

Step 4: For each item in moz_results's results:
  If Domain_Authority exists where domain = item's page:
    Make changes: da=item's domain_authority, pa=item's page_authority,
                  spam_score=item's spam_score, fetched_date=current date
  Else:
    Create Domain_Authority: domain=item's page, da=item's domain_authority,
    pa=item's page_authority, spam_score=item's spam_score,
    root_domains=item's root_domains_to_root_domain,
    equity_links=item's external_equity_links, fetched_date=current date

Batch cap: 50 domains per POST request
For lists > 50: use recursive Backend Workflow, batch items 1-50, then 51-100, etc.
```

**Expected result:** Submitting a list of domains triggers the workflow. After completion, Domain_Authority records exist for each domain with correct DA, PA, and Spam Score values and a current fetched_date.

### 6. Build the sortable Repeating Group with DA color-coding

With data stored in Domain_Authority, the Repeating Group display is straightforward and highly customizable. Select your Repeating Group on the canvas. Configure:
- Type of content: Domain_Authority
- Data source: Do a search for Domain_Authority items, sorted by da descending

Add filtering controls: a Number Input for minimum DA threshold and a Checkbox for 'Only show Spam Score < 30'. Connect these to the data source with constraints.

Inside the Repeating Group cell, add Text elements:
- Domain: Current cell's Domain_Authority's domain
- DA Score: Current cell's Domain_Authority's da (formatted as number)
- PA Score: Current cell's Domain_Authority's pa
- Spam Score: Current cell's Domain_Authority's spam_score
- Last Updated: Current cell's Domain_Authority's fetched_date (formatted as 'MMM D, YYYY')

For the DA Score text element, add Conditional styling:
- Conditional 1: When Current cell's Domain_Authority's da > 69 → Background color: green (light)
- Conditional 2: When Current cell's Domain_Authority's da > 39 AND ≤ 69 → Background color: yellow (light)
- Conditional 3: When Current cell's Domain_Authority's da ≤ 39 → Background color: red (light)

Add a 'Force Refresh' icon button for each row that triggers a single-domain batch_url_metrics call (with a one-domain targets array) and updates the specific Domain_Authority record. This gives users an escape valve when they know a domain's authority has changed recently without waiting for the 30-day cache expiry.

```
Repeating Group configuration:
  Type of content: Domain_Authority
  Data source: Search Domain_Authority
    Constraint: da ≥ MinimumDA Input's value (optional filter)
    Sort: da, Descending

Cell elements:
  Text 'Domain': Current cell's Domain_Authority's domain
  Text 'DA': Current cell's Domain_Authority's da
    Conditional: da > 69 → background #d4edda (green)
    Conditional: da 40-69 → background #fff3cd (yellow)
    Conditional: da < 40 → background #f8d7da (red)
  Text 'PA': Current cell's Domain_Authority's pa
  Text 'Spam': Current cell's Domain_Authority's spam_score
    Conditional: spam_score > 30 → text color red, add warning icon
  Text 'Updated': Current cell's Domain_Authority's fetched_date
    Format: MMM D, YYYY

Force Refresh button workflow:
  Step 1: Call batch_url_metrics
    Body: {"targets": ["[Current cell's Domain_Authority's domain]"]}
  Step 2: Make changes to Current cell's Domain_Authority
    da: Result Step 1's results:first item's domain_authority
    pa: Result Step 1's results:first item's page_authority
    spam_score: Result Step 1's results:first item's spam_score
    fetched_date: Current date/time
```

**Expected result:** The Repeating Group displays domains in DA descending order with color-coded DA badges. Green for high DA, yellow for medium, red for low. The Force Refresh button correctly updates individual records on demand.

## Best practices

- Always pre-compute the base64 Basic Auth string outside Bubble (using btoa() in your browser console) before configuring the API Connector. Bubble has no native Basic Auth UI, and attempting to build the encoding in Bubble workflows adds unnecessary complexity. Document the computation step in your app's internal notes so future developers know how to regenerate it if credentials change.
- Mark the Authorization header Private in the API Connector. Even though the base64 encoding is technically reversible, the Private checkbox ensures Bubble never includes this header in client-side responses — keeping your Moz credentials server-side only.
- Cache DA/PA results in a Domain_Authority Data Type with a 30-day expiry. Moz updates scores monthly, so calling the API more frequently is wasteful. Check fetched_date before every lookup and skip the API call if data is fresh.
- Set privacy rules on the Domain_Authority Data Type immediately. Your competitor DA data is business intelligence — ensure 'Everyone else' cannot read or search these records via Bubble's Data API or through unprotected page elements.
- Never exceed 50 domains per POST /url_metrics call. The Moz API rejects batches larger than 50 with an error. For lists exceeding 50 domains, implement a recursive Backend Workflow that processes exactly 50 per iteration.
- Monitor your Moz API credit consumption via the API usage dashboard at moz.com. Standard plans include enough credits for small-scale use (hundreds of domains per month), but large link-building databases with hundreds of new prospects added weekly can approach plan limits. Upgrade to the Medium plan if necessary.
- Store the Moz Access ID and Secret Key separately from the base64-computed string in your password manager. If you rotate credentials, you will need to recompute the base64 string — having the raw credentials available makes this a 10-second task rather than a Moz dashboard lookup.
- Add a WU-conscious note to your Bubble documentation: the batch Backend Workflow that loops through large domain lists and creates Domain_Authority records consumes WU proportional to the list length. Batch daily refreshes overnight (scheduled Backend Workflow) rather than during peak hours when your Bubble WU pool is under heavier demand.

## Use cases

### Link-building CRM with bulk DA scoring

Build a Bubble database of link prospects (competitor sites, media publications, industry directories). Add a 'Score Domains' button that triggers a batch POST /url_metrics call for up to 50 domains at once, stores the returned DA, PA, and Spam Score in Domain_Authority records, and updates a sortable Repeating Group. Your outreach team can filter by DA threshold (e.g., only show DA 50+) and track which prospects have been contacted without leaving Bubble.

Prompt example:

```
Build a link-building tracker in Bubble where I can add domain names to a list, click 'Get Moz Scores' to batch-call the Moz API for up to 50 domains, store DA/PA/Spam Score in a Domain_Authority Data Type, and display results in a table sorted by DA descending with color-coding: green for DA 70+, yellow for 40-69, red below 40.
```

### Competitor DA monitoring dashboard

Track a fixed list of competitor domains over time by running a weekly Moz batch lookup and storing historical DA snapshots. Display a Bubble chart showing DA trends for each competitor across multiple time periods, letting your SEO team identify when competitor authority changes significantly and adjust strategy accordingly.

Prompt example:

```
Create a Bubble admin dashboard that stores a fixed list of 20 competitor domains, runs a weekly Backend Workflow to fetch their Moz DA scores, creates a DATrend record per domain per week, and displays a line chart showing each competitor's DA over the past 12 weeks.
```

### SEO audit intake with automatic authority scoring

When a client submits their website URL through a Bubble intake form for an SEO audit, automatically call the Moz API to pull the domain's current DA, PA, and Spam Score and attach it to the audit record. The SEO team starts every audit with baseline authority data already populated, saving 15-20 minutes of manual lookups.

Prompt example:

```
In my Bubble SEO audit intake form, when a new Audit record is created with a domain URL, automatically call the Moz Links API to fetch the domain's DA, PA, and Spam Score and save them as fields on the Audit record — so the assigned analyst sees these scores immediately on the audit detail page.
```

## Troubleshooting

### All Moz API calls return 401 Unauthorized

Cause: The three most common causes: (1) raw credentials pasted instead of base64-encoded string, (2) missing 'Basic ' prefix (with space) before the base64 string in the header value, or (3) the colon separator between Access ID and Secret Key was missing in the btoa() computation.

Solution: Re-run the btoa() computation in your browser console. Confirm the format is exactly: btoa('YOUR_ACCESS_ID:YOUR_SECRET_KEY') — including the colon between them. Copy the output. In the API Connector Authorization header value, ensure the full value is: Basic [output] — the word 'Basic' followed by a space, then the base64 string. Update the API Connector header with the corrected value and re-initialize the call.

```
// Correct computation (run in browser console):
btoa('mozscape-xxxxxxxxxxxxxxxx:your-secret-key')
// Output: 'bW96c2NhcGUteHh4...' (paste this after 'Basic ')

// Full header value: Basic bW96c2NhcGUteHh4...
```

### API call returns 403 Forbidden — no API access is available on my Moz account

Cause: Moz's API requires a paid Moz Pro plan (Standard tier ~$99/mo or above). Free Moz accounts do not show an API key or Access ID in the dashboard, and attempting to use any credential returns 403.

Solution: Log in to moz.com and check your subscription at moz.com/products/pro/api. If the API section is not visible, your account needs to be upgraded to a Pro plan. After upgrading, wait a few minutes for the API access to activate, then retrieve your Access ID and Secret Key from the API dashboard.

### Initialize call fails with 'There was an issue setting up your call'

Cause: The batch_url_metrics POST call requires a valid JSON body with a real domain in the targets array. If the body is malformed or the targets array is empty, Moz returns an error and Bubble cannot detect field types.

Solution: During initialization, manually enter a valid JSON body in the Body field of the API Connector call configuration: {"targets": ["moz.com"]}. Use a well-known domain that Moz has data for. Ensure the Content-Type: application/json shared header is present and not marked Private. After a successful initialization against moz.com, field types will be detected and you can modify the call to accept dynamic domain lists.

```
// Correct initialization body for the API Connector:
{
  "targets": ["moz.com"]
}
```

### The API returns results in a different order than the domains I submitted

Cause: This is a misunderstanding — the Moz API actually returns results in the SAME ORDER as the targets array. If results appear out of order, the targets array sent in the POST body was not in the expected order.

Solution: When processing results in a Bubble Workflow loop, use the index position to match results to targets: results item #1 corresponds to targets item #1, results item #2 to targets #2, and so on. Use Bubble's ':item # [index]' operator to access results positionally when storing to Domain_Authority records. Do not rely on the domain field in the response for matching — always use position.

### Attempting to submit 51+ domains results in an API error

Cause: The Moz /url_metrics endpoint has a hard batch limit of 50 URLs per request. Any request with more than 50 items in the targets array returns an error.

Solution: Split your domain list into chunks of 50 before sending. For lists up to 50 domains, a single API call is sufficient. For larger lists, implement a recursive Backend Workflow: the first iteration processes domains 1-50, creates Domain_Authority records, then schedules itself to run again with domains 51-100, and so on until all domains are processed. Note: recursive Backend Workflows on very long lists can approach Bubble's 30-second workflow timeout per step — design each iteration to do only one batch of 50 and schedule the next iteration before the timeout.

## Frequently asked questions

### Why does Bubble's API Connector not have a Basic Auth option?

Bubble's API Connector supports custom headers but does not include a native Basic Auth radio button like some other API clients (Postman, Retool, etc.) do. This is a known limitation. The workaround is to manually compute the base64-encoded string for the Authorization header value before configuring the connector. Open your browser console, run btoa('ACCESS_ID:SECRET_KEY'), and paste the result prefixed with 'Basic ' into the Authorization header value — then mark it Private. This is a one-time step that does not need to be repeated unless credentials change.

### How many domains can I check per Moz API call?

The POST /url_metrics endpoint accepts a maximum of 50 URLs per request in the targets array. Attempting to send 51 or more returns an API error. For link-building databases with more than 50 domains, implement batching: split your list into groups of 50 and either run them sequentially in a Backend Workflow or process them in separate workflow runs. Each URL in a batch counts as one API credit against your Moz plan limit.

### Do I need a paid Bubble plan to use the Moz API?

For basic outbound DA lookups triggered by button clicks, the free Bubble tier works. You only need a paid Bubble plan (Starter $32/mo+) for Backend Workflows — which you will need for scheduled weekly DA refreshes, recursive batch processing for large domain lists, or any server-side automation. For the core link-building CRM described in this guide with up to 50 domains processed per user action, the free Bubble tier is sufficient.

### Why does the Moz API return results in the same order as my input? Is that guaranteed?

Yes — the /url_metrics endpoint is documented to return results in the same positional order as the targets array in your request. This is intentional and reliable. The response position 0 corresponds to target 0, position 1 to target 1, and so on. Use this ordering guarantee when mapping API responses back to your Bubble Data Type records — access results by position ([index]) rather than by trying to match on domain name.

### My Moz DA scores are outdated. How often does Moz update them?

Moz updates Domain Authority scores approximately monthly as part of their regular index crawl and metric recalculation cycle. If the DA score in your Bubble app seems outdated, check the fetched_date on the Domain_Authority record — if it is less than 30 days old, the score is current as of the last Moz update. If you need the absolute latest score, use the 'Force Refresh' button to make a fresh API call for that specific domain.

### Can I check Page Authority (PA) for specific URLs, not just root domains?

Yes — the /url_metrics endpoint accepts both root domains (competitor.com) and full URLs (competitor.com/specific-page). When you submit a full URL, the response includes both the page_authority for that specific page and the domain_authority for the root domain. For link-building prospecting where specific pages (like resource pages or blog posts) are the target, submitting the full URL gives you more granular authority data.

---

Source: https://www.rapidevelopers.com/bubble-integrations/moz
© RapidDev — https://www.rapidevelopers.com/bubble-integrations/moz
