Find Companies Using WordPress Block Editor (API Guide)

July 25, 2026 · 10 min read

Knowing a company runs WordPress narrows a prospect list from the whole web down to roughly two out of every five sites on it. That is not much of a filter. Knowing how they build pages inside WordPress is a much sharper cut, because it tells you which editing workflow the team actually lives in, which plugins are likely installed, and which pitch will land. This guide covers the Block Editor — the block-based editor shipped in WordPress core, still widely called Gutenberg — how it is detectable from outside the site, and how to turn that into a filtered list with the DetectZeStack API. Every response below comes from a live scan of a real domain.

Why WordPress Block Editor Is a Useful Buying Signal

The Block Editor became the WordPress default in late 2018, and by now its presence in a site's HTML says something specific: this site's content was built, or at least rebuilt, on a modern WordPress workflow rather than left on decade-old classic markup. That distinction matters for anyone selling into the WordPress market. A site rendering block markup has an editor who works with blocks, a theme that supports them, and a maintenance posture current enough to have made the transition.

It also tells you what the site is not doing. Sites built on a commercial page builder tend to render that builder's markup instead, and the two rarely dominate the same pages. If your product is a block library, a block-native theme, a headless front end that consumes the WordPress REST API, or a migration service off a legacy builder, the block signal separates your addressable market from everyone else's.

Block Editor vs. Classic Editor vs. Page Builders

Three editing workflows coexist across the WordPress install base, and they leave different traces:

Workflow What it renders What it tells you about the buyer
Block Editor Container divs with wp-block- class names On a current WordPress workflow; open to block-native products
Classic Editor Plain, unwrapped post HTML with no block containers Older content, possibly a deliberate hold-back; migration and maintenance lead
Page builder Builder-specific markup and asset paths, e.g. Elementor Committed to a commercial builder; sells differently, often via the builder ecosystem

A live example of the third row: a scan of elementor.com returns Elementor, Elementor Cloud, and WordPress — and no WordPress Block Editor entry at all. The absence is the signal. That site is not a block-library prospect; it is a builder-ecosystem prospect. The Elementor detection guide covers that side of the split.

How Block Editor Detection Actually Works

The wp-block-* Class Fingerprint in Rendered HTML

The Block Editor stores content as block markup and renders each block into a container element on the public page. Those containers carry generated class names in a predictable namespace:

<div class="wp-block-group">
  <h2 class="wp-block-heading">Pricing</h2>
  <div class="wp-block-columns">
    <div class="wp-block-column">...</div>
    <div class="wp-block-column">...</div>
  </div>
</div>

DetectZeStack matches a container div whose class attribute starts with wp-block- in the HTML the server returns. Two properties make this a good fingerprint. First, it is server-rendered: the markup is present in the initial HTML response, so no JavaScript execution is required to see it, which is why the detection comes back with "source": "http". Second, nothing else produces that namespace by accident — wp-block- classes come from the WordPress block system.

One thing the fingerprint does not give you is a version. There is no version string embedded in block markup, so the version field on this detection is always empty. If you need a version to qualify on, use the WordPress detection alongside it, which does report a core version when the site exposes one.

Related Signals: WordPress Site Editor and the Gutenberg Plugin

Two neighbouring detections often appear on the same scan, and they mean different things:

A live scan of wordpress.org returns all three at once — Gutenberg, WordPress Block Editor, and WordPress Site Editor, alongside WordPress itself. That is the maximal case. A scan of techcrunch.com returns the Block Editor and the Site Editor but not the plugin, which is what a large, professionally-run block-based site typically looks like.

Why Manual View-Source Checks Break at Scale

You can verify any single domain by hand: open the page, view source, search for wp-block-. That works fine once. It breaks in three ways as soon as you have a list. You have to visit every site, which is slow and leaves your footprint on each one. You get a yes or no and nothing else — no hosting, no plugins, no theme context to qualify with. And you cannot easily distinguish "no block markup" from "the site returned a 403 to my request", which is the difference between a real negative and a row you should retry.

Check a Single Domain With the DetectZeStack API

GET /demo for a Keyless First Look

The /demo endpoint needs no API key and no signup, so start there. TechCrunch is a real block-based WordPress site:

curl -s "https://detectzestack.com/demo?url=techcrunch.com" \
  | jq '.technologies[] | select(.name == "WordPress Block Editor")'

Which returns:

{
  "name": "WordPress Block Editor",
  "categories": [
    "Page builders"
  ],
  "confidence": 100,
  "description": "Sites using the WordPress Block Editor, also known as Gutenberg.",
  "website": "https://wordpress.org/gutenberg/",
  "icon": "WordPress.svg",
  "source": "http"
}

Read the fields that matter. categories places the Block Editor under Page builders, which is where you look for it when slicing a scan by category. confidence is 100 because the markup matched directly. source is http, meaning the evidence came from the HTML response rather than a DNS or TLS signal. And there is no version key in the output, because the fingerprint carries none.

GET /check for a Yes/No Answer on One Technology

When all you need is a boolean, /check answers directly. Note the URL-encoded spaces in the technology name; the parameter is case insensitive and the response echoes back the canonical name:

curl -s "https://detectzestack.p.rapidapi.com/check?url=techcrunch.com&tech=WordPress%20Block%20Editor" \
  -H "X-RapidAPI-Key: YOUR_KEY" \
  -H "X-RapidAPI-Host: detectzestack.p.rapidapi.com" | jq '.'
{
  "domain": "techcrunch.com",
  "technology": "WordPress Block Editor",
  "detected": true,
  "confidence": 100,
  "version": "",
  "categories": ["Page builders"],
  "response_ms": 388,
  "cached": false
}

The empty version is expected here, not an error. detected is the field to branch on.

GET /analyze for the Full Stack Around the Block Editor

The boolean is rarely the interesting part. The full /analyze response is what turns a domain into a lead, because it returns everything else the scan found. Here is the same TechCrunch scan, trimmed to the fields that matter for prospecting:

curl -s "https://detectzestack.p.rapidapi.com/analyze?url=techcrunch.com" \
  -H "X-RapidAPI-Key: YOUR_KEY" \
  -H "X-RapidAPI-Host: detectzestack.p.rapidapi.com" | jq '.'
{
  "url": "https://techcrunch.com",
  "domain": "techcrunch.com",
  "technologies": [
    { "name": "WordPress",             "categories": ["CMS", "Blogs"],       "confidence": 100, "version": "6.9.5", "source": "http" },
    { "name": "WordPress Block Editor","categories": ["Page builders"],      "confidence": 100, "version": "",      "source": "http" },
    { "name": "WordPress Site Editor", "categories": ["Page builders"],      "confidence": 100, "version": "",      "source": "http" },
    { "name": "WordPress VIP",         "categories": ["PaaS"],               "confidence": 100, "version": "",      "source": "http" },
    { "name": "Yoast SEO",             "categories": ["SEO", "WordPress plugins"], "confidence": 100, "version": "25.1", "source": "http" },
    { "name": "Nginx",                 "categories": ["Web servers", "Reverse proxies"], "confidence": 100, "version": "", "source": "http" },
    { "name": "PHP",                   "categories": ["Programming languages"], "confidence": 100, "version": "",   "source": "http" },
    { "name": "MySQL",                 "categories": ["Databases"],          "confidence": 100, "version": "",      "source": "http" },
    { "name": "Google Tag Manager",    "categories": ["Tag managers"],       "confidence": 100, "version": "",      "source": "http" },
    { "name": "Let's Encrypt",         "categories": ["SSL/TLS certificate authority"], "confidence": 100, "version": "", "source": "tls" }
  ],
  "categories": {
    "Page builders": ["WordPress Site Editor", "WordPress Block Editor"],
    "CMS": ["WordPress"],
    "PaaS": ["WordPress VIP"],
    "SEO": ["Yoast SEO"]
  },
  "meta": { "status_code": 200, "tech_count": 14, "scan_depth": "full" },
  "cached": false,
  "response_ms": 1704
}

That single call is a sales brief: block-based WordPress 6.9.5, on WordPress VIP managed hosting, behind Nginx, with Yoast SEO and Google Tag Manager. The categories map makes the block check a one-line lookup in code — test whether categories["Page builders"] contains WordPress Block Editor — and the PaaS entry tells you the account size bracket before you have spoken to anyone.

Build a List of Companies Using WordPress Block Editor

POST /analyze/batch to Scan a Domain List

Batch is how you work through a list. It accepts up to 10 URLs per request, scans them concurrently, and returns one item per URL with its own error field so one bad domain does not fail the whole batch:

curl -s -X POST "https://detectzestack.p.rapidapi.com/analyze/batch" \
  -H "X-RapidAPI-Key: YOUR_KEY" \
  -H "X-RapidAPI-Host: detectzestack.p.rapidapi.com" \
  -H "Content-Type: application/json" \
  -d '{"urls": ["techcrunch.com", "kinsta.com", "wpbeginner.com", "elementor.com"]}' \
  | jq -r '.results[]
      | select(.result.technologies[]?.name == "WordPress Block Editor")
      | .result.domain'

Run against those four real domains, that filter returns techcrunch.com and kinsta.com. Both wpbeginner.com and elementor.com are WordPress sites, and neither returns a Block Editor detection — a useful reminder that "runs WordPress" and "renders blocks" are genuinely different populations.

Each URL in a batch counts as one request against your monthly quota, so a 10-URL batch costs 10 requests. Batching saves round trips and wall-clock time, not quota. For lists in the hundreds or thousands, the batch scanning guide covers pacing, retries, and cost.

Filtering Results Down to Block Editor Adopters in Python

Putting it together: read domains from a file, scan in batches of 10, keep the block-based sites, and record the neighbouring signals you will qualify on.

import csv
import requests

API = "https://detectzestack.p.rapidapi.com/analyze/batch"
HEADERS = {
    "X-RapidAPI-Key": "YOUR_KEY",
    "X-RapidAPI-Host": "detectzestack.p.rapidapi.com",
    "Content-Type": "application/json",
}
BATCH_SIZE = 10  # API maximum per request


def scan(domains):
    """Scan up to 10 domains, yielding (domain, technologies, status_code)."""
    resp = requests.post(API, headers=HEADERS, json={"urls": domains}, timeout=60)
    resp.raise_for_status()
    for item in resp.json()["results"]:
        result = item.get("result")
        if not result:
            print(f"  skipped {item['url']}: {item.get('error', 'no result')}")
            continue
        status = result.get("meta", {}).get("status_code")
        yield result["domain"], result.get("technologies", []), status


def main():
    with open("domains.txt") as f:
        domains = [line.strip() for line in f if line.strip()]

    prospects, inconclusive = [], []
    for i in range(0, len(domains), BATCH_SIZE):
        chunk = domains[i:i + BATCH_SIZE]
        print(f"Scanning {i + 1}-{i + len(chunk)} of {len(domains)}...")
        for domain, techs, status in scan(chunk):
            if status != 200:
                # No page HTML means no block markup to match on.
                inconclusive.append(domain)
                print(f"  {domain}: status {status}, inconclusive")
                continue

            names = {t["name"] for t in techs}
            if "WordPress Block Editor" not in names:
                continue

            wp = next((t for t in techs if t["name"] == "WordPress"), None)
            prospects.append({
                "domain": domain,
                "wordpress_version": wp.get("version", "") if wp else "",
                "site_editor": "WordPress Site Editor" in names,
                "gutenberg_plugin": "Gutenberg" in names,
                "stack": ", ".join(sorted(names)),
            })
            print(f"  {domain}: block editor detected")

    with open("block_editor_prospects.csv", "w", newline="") as f:
        writer = csv.DictWriter(
            f,
            fieldnames=["domain", "wordpress_version", "site_editor",
                        "gutenberg_plugin", "stack"],
        )
        writer.writeheader()
        writer.writerows(prospects)

    print(f"\n{len(prospects)} block editor sites out of {len(domains)} domains.")
    print(f"{len(inconclusive)} inconclusive, retry later: {inconclusive}")


if __name__ == "__main__":
    main()

The caveat that matters most: check meta.status_code. The Block Editor is detected from rendered HTML. If a site answers your scan with a 403 or 429 instead of its page, there is no block markup to match, and the detection will be missing even on a site that is entirely block-built. Treat any non-200 status_code as inconclusive rather than negative and retry those rows, or you will quietly drop real prospects.

Qualify the Leads You Find

POST /compare to Contrast Two Prospects' Stacks

/compare takes 2 to 10 URLs and returns, per domain, the technologies unique to it, plus the set shared across all of them. It is the fastest way to see how two prospects differ:

curl -s -X POST "https://detectzestack.p.rapidapi.com/compare" \
  -H "X-RapidAPI-Key: YOUR_KEY" \
  -H "X-RapidAPI-Host: detectzestack.p.rapidapi.com" \
  -H "Content-Type: application/json" \
  -d '{"urls": ["techcrunch.com", "elementor.com"]}' \
  | jq '{shared: .shared,
         techcrunch_only: .domains[0].unique,
         elementor_only: .domains[1].unique}'

The shared set comes back with the platform floor both sites stand on — WordPress, PHP, MySQL, Yoast SEO, Google Tag Manager, Let's Encrypt, HSTS — while the unique lists carry the difference that actually matters: WordPress Block Editor, WordPress Site Editor, and WordPress VIP on one side, Elementor and Elementor Cloud on the other. Two WordPress sites, two incompatible pitches, one API call to tell them apart.

Layering Hosting, Plugin, and Theme Signals

The Block Editor is a qualifier, not a lead score on its own. Layer it:

If you want the platform layer beneath all of this, finding companies using WordPress and checking whether a website uses WordPress cover the same mechanics one level down, and detecting what CMS a website uses covers the case where you do not yet know the platform at all.

Detection Limits and False Negatives to Expect

Be honest with yourself about what an absent detection means. It is an unknown, not a no. Four common causes:

  1. The scanned page is not block-built. A site can run a block-based blog and a hand-coded or builder-built homepage. Scans hit the homepage by default, so the homepage is what you learn about.
  2. Classic content. Posts written before the Block Editor keep their original markup indefinitely. A long-running site can be fully modern in wp-admin and still serve classic HTML on old URLs.
  3. Markup rewriting. Aggressive optimization, CSS-pruning, or HTML-minifying layers can alter or strip the class attributes the fingerprint depends on. This is the least common cause and the hardest to distinguish from a genuine negative.
  4. The scan never saw the page. Bot protection, rate limiting, and geo-blocking all produce a non-200 response. Check meta.status_code on every result, every time.

The practical discipline is a three-state model in your pipeline — detected, not detected, inconclusive — rather than a boolean column. The Python example above keeps the inconclusive rows in their own list for exactly this reason.

Free Demo Endpoint and Getting an API Key

Validate the whole approach before paying for anything. The keyless /demo endpoint runs a full scan on any domain:

curl -s "https://detectzestack.com/demo?url=kinsta.com" \
  | jq '{domain, block_editor: (.categories["Page builders"] // []), status: .meta.status_code}'
{
  "domain": "kinsta.com",
  "block_editor": [
    "WordPress Block Editor"
  ],
  "status": 200
}

When you are ready for authenticated endpoints, plans are the standard DetectZeStack tiers, and every URL scanned counts as one request:

Plan Price Requests / month
BasicFree100
Pro$91,000
Ultra$2910,000
Mega$7950,000

Results are cached for 24 hours by default, and a cache hit returns "cached": true with a near-zero response_ms. The free plan's 100 monthly requests are enough to run a real slice of your target list end to end before spending anything.

Conclusion

The Block Editor is a precise signal hiding inside a vague one. "Runs WordPress" covers a huge and internally contradictory population; "renders block markup" picks out the part of it on a current workflow, and it does so from a single server-rendered class-name pattern that needs no JavaScript to see. Start with /demo on a domain you already know, use /check when you want a boolean, /analyze when you want the surrounding stack, and /analyze/batch when you have a list. Keep the status_code guard in every pipeline, treat missing detections as inconclusive, and the list you build will be one you can actually trust.

Related Reading

Start Finding Block Editor Sites Today

100 free API requests/month. No credit card required. Detect the WordPress Block Editor and thousands of other technologies.

Get Your Free API Key

Get API updates and tech detection tips

Join the mailing list. No spam, unsubscribe anytime.