magendoo / module-catalog-quality
Catalog data quality observability for Magento 2 — completeness scoring, filter-blind detection, and gap reporting
Package info
github.com/magendooro/magento2-catalog-quality
Type:magento2-module
pkg:composer/magendoo/module-catalog-quality
Fund package maintenance!
Requires
- php: >=8.2
- magento/framework: >=103.0
- magento/module-backend: >=102.0
- magento/module-catalog: >=104.0
- magento/module-eav: >=102.0
- magento/module-indexer: >=100.4
- magento/module-store: >=101.0
- magento/module-ui: >=101.2
README
Catalog data quality observability for Magento 2.
Know exactly which products are hurting your conversion rate before your customers find out.
What It Does
Magendoo_CatalogQuality scores every product in your catalog against a two-axis quality model — Enrichment (are the important attributes filled in?) and Consistency (do they meet your content rules?) — and combines them into a single Product Health Score (PHS) between 0 and 100. Products are graded A–E.
The module answers three questions that every Magento merchant needs:
- Which products are incomplete? — The Gap List shows every product's grade, PHS, priority gaps, and the specific missing attribute codes.
- Which products are invisible in layered navigation? — The Filter-Blind detector flags products that have no value for a filterable attribute, making them unfindable when shoppers use your category filters.
- Which filter attributes have the worst coverage across categories? — The Filter Coverage Matrix shows fill rates as a colour-coded heatmap, scoped by attribute set.
No auto-fix. No AI. Just clear, actionable diagnostic data.
Screenshots
Dashboard
The dashboard shows the Catalog Health Index (CHI) — a revenue-weighted average PHS across all scored products — alongside grade distribution, filter-blind product count, and a 30-day CHI trend chart.
Product Gap List
Every scored product in one grid: grade badge, PHS, P1/P2/P3 gap counts, a filter-blind chip, and colour-coded missing attribute chips. Red chips are filterable attributes directly causing filter-blindness; grey chips are other priority gaps.
Filter Coverage Matrix
Rows are user-defined filterable attributes; columns are active categories (filterable by attribute set). Each cell shows the fill-rate percentage, colour-coded from green (≥90 %) to red (<35 %). Click a cell to open the Gap List pre-filtered by that attribute and category.
Features
- Two-axis PHS scoring: Enrichment completeness × Consistency conformance multiplier
- A–E grade thresholds: ≥90 → A, ≥80 → B, ≥70 → C, ≥50 → D, <50 → E
- Revenue-weighted CHI: weights products by 90-day revenue when sales data is available
- Filter-blind detection: flags products invisible in layered navigation per store view
- Attribute Priority System: P1/P2/P3/P4/Ignore per attribute, with category and attribute-set overrides
- Placeholder blocklist: regex and literal patterns to catch values like "N/A", "TBD", "Lorem ipsum"
- 9 built-in quality rules: Meta Title, Meta Description, URL Key, Name, Description, Image, Category, Price, Filterable Attribute
- Conditional attribute groups: score module-specific attributes only when their control flag is on (e.g. base-price fields only when
baseprice_is_enabled = 1) - Magento indexer integration: incremental updates via MView, full reindex via CLI
- Nightly CHI snapshots: 30-day trend data stored automatically via cron
- CSV export of the Gap List and Priority table
- REST API: 6 endpoints for scores and priorities
- Inline-editable Priority Grid: change priority levels without leaving the listing
- Filter Coverage Matrix: attribute set filter, product counts per category column, click-through to Gap List
Requirements
| Dependency | Version |
|---|---|
| PHP | ≥ 8.2 |
| Magento Open Source / Adobe Commerce | 2.4.x |
magento/framework |
≥ 103.0 |
magento/module-catalog |
≥ 104.0 |
Installation
Via Composer (recommended)
composer require magendoo/module-catalog-quality bin/magento module:enable Magendoo_CatalogQuality bin/magento setup:upgrade bin/magento setup:di:compile bin/magento setup:static-content:deploy -f bin/magento cache:flush
Manual
- Copy the module directory into
app/code/Magendoo/CatalogQuality/ - Run the same CLI commands above
Initial Setup
After installation, run the full indexer to score all products:
bin/magento indexer:reindex magendoo_cq_product_score
This may take several minutes on large catalogs. The batch size is configurable under Stores → Configuration → Magendoo Extensions → Catalog Quality → Performance.
Admin Screens
Navigate to Catalog Quality in the top-level admin menu.
| Screen | URL | Description |
|---|---|---|
| Dashboard | /catalogquality/dashboard/index |
CHI, grade distribution, filter-blind count, 30-day trend |
| Product Gap List | /catalogquality/gaps/index |
All scored products; filterable by grade, filter-blind status |
| Filter Coverage Matrix | /catalogquality/filters/index |
Attribute fill-rate heatmap per category |
| Attribute Priorities | /catalogquality/priority/index |
Inline-editable priority rules |
Configuration
Stores → Configuration → Magendoo Extensions → Catalog Quality
| Setting | Default | Description |
|---|---|---|
| Enabled | Yes | Master switch |
| Revenue-weighted CHI | Yes | Weight CHI by 90-day product revenue |
| Indexer Batch Size | 500 | Products scored per batch during full reindex |
| Snapshot Retention | 90 days | How long nightly CHI snapshots are kept |
Scoring Algorithm
See docs/scoring-algorithm.md for the full specification.
Summary:
PHS(product, store_view) =
[Σ weight(attr) × completeness_score(attr)] / [Σ weight(attr)] ← enrichment
× conformance_multiplier ← consistency
× 100
completeness_score: empty / placeholder → 0.0 | present → 0.5 | meets_bar → 1.0
conformance_mult: 1.0 baseline; CRITICAL rule failure × 0.7; WARNING × 0.9
CHI = Σ(revenue_90d × PHS) / Σ(revenue_90d) (falls back to equal-weight)
Priority System
See docs/priority-system.md for the full hierarchy.
Quick reference:
| Level | Weight | Meaning |
|---|---|---|
| P1 | 100 | Critical — directly impacts conversions (name, price, image, meta) |
| P2 | 50 | Important — filterable attributes auto-floor here |
| P3 | 20 | Standard — user-defined attributes not yet classified |
| P4 | 5 | Low — nice-to-have |
| Ignore | 0 | Never scored (system attrs, optional promotional fields) |
Priority resolution order (first match wins):
- Explicit row with matching
category_id - Explicit row with matching
attribute_set_id - Explicit global row (no set, no category)
- Implicit: SEO attrs → P1; user-defined filterable → P2; user-defined → P3; else → Ignore
Conditional Attribute Groups
Some module attributes should only be scored when they are relevant for a specific product. Configure this in etc/di.xml:
<type name="Magendoo\CatalogQuality\Model\Scoring\ProductScorer"> <arguments> <argument name="conditionalGroups" xsi:type="array"> <item name="baseprice" xsi:type="array"> <item name="enabledBy" xsi:type="string">baseprice_is_enabled</item> <item name="attributes" xsi:type="array"> <item name="0" xsi:type="string">baseprice_product_amount</item> <item name="1" xsi:type="string">baseprice_unit_id</item> <item name="2" xsi:type="string">baseprice_reference_amount</item> </item> </item> </argument> </arguments> </type>
The enabledBy attribute is never scored itself — it acts as a gate. The listed attributes are only evaluated when the gate attribute is truthy (1). The example above wires up Magendoo_BasePrice so that unit-pricing compliance fields only count as gaps on products where base pricing is switched on.
CLI Commands
# Full reindex — score all products (optionally scoped to a store) bin/magento catalog-quality:rebuild [--store=<store_id>] [--batch=<size>] # Debug a single product bin/magento catalog-quality:score <sku> [--store=<store_id>] # Example output: # {"sku":"WH-X500","grade":"D","phs":42.15,"filter_blind":true,"p1_gaps":1,"p2_gaps":2,"missing":["cq_connectivity","cq_color"]} # Export priorities to CSV bin/magento catalog-quality:priorities:export [--set=<attribute_set_id>] [--format=csv]
REST API
See docs/rest-api.md for request/response schemas.
| Method | Endpoint | Description |
|---|---|---|
GET |
/V1/catalog-quality/scores/:sku |
Get quality score for a single SKU |
GET |
/V1/catalog-quality/gaps |
List gap records (supports search criteria) |
POST |
/V1/catalog-quality/priorities |
Create or update a single priority rule |
POST |
/V1/catalog-quality/priorities/bulk |
Bulk upsert priority rules |
GET |
/V1/catalog-quality/priorities |
List priority rules |
DELETE |
/V1/catalog-quality/priorities/:id |
Delete a priority rule |
All endpoints require an admin bearer token. Authenticate with POST /V1/integration/admin/token.
Database Tables
| Table | Purpose |
|---|---|
magendoo_cq_priority |
Attribute priority rules (P1–P4/Ignore) per attribute, set, and category |
magendoo_cq_priority_history |
Audit log of priority changes |
magendoo_cq_product_score |
Per-product PHS, grade, gap counts, filter-blind flag |
magendoo_cq_attribute_score |
Per-attribute value states for a product |
magendoo_cq_catalog_snapshot |
Nightly CHI snapshots for trend charts |
magendoo_cq_scope_profile |
Named scope profiles (sellable, pre-launch, full catalog) |
magendoo_cq_rule_config |
Per-rule enabled/severity/parameter overrides |
magendoo_cq_placeholder_blocklist |
Literal and regex patterns for placeholder detection |
magendoo_cq_remediation_queue |
Remediation work queues (Phase 2) |
magendoo_cq_remediation_queue_item |
Items within a remediation queue |
magendoo_cq_rule_run_log |
Indexer run audit log |
Extending
Adding a Custom Quality Rule
- Implement
Magendoo\CatalogQuality\Api\RuleInterface - Register it in
etc/di.xmlunderRulePool
<type name="Magendoo\CatalogQuality\Model\Rule\RulePool"> <arguments> <argument name="rules" xsi:type="array"> <item name="my_custom_rule" xsi:type="object"> Vendor\Module\Model\Rule\Enrichment\MyCustomRule </item> </argument> </arguments> </type>
Adding a Conditional Attribute Group
Register a conditionalGroups item as shown in the Conditional Attribute Groups section above.
License
MIT — © 2025 Magendoo Interactive


