Customer-specific catalogs and pricing strategy explained
Shared Catalogs control, for every company, which categories are visible and at what prices products can be ordered, built on the same Category Permissions that also exist outside the B2B Suite. Understanding the mechanics behind it lets teams control visibility and price overrides deliberately, instead of getting surprised by indexing problems once the catalog count grows.
Table of Contents
- 1. Placing Shared Catalogs in a B2B context
- 2. Technical setup: a hidden customer group and Category Permissions
- 3. Keeping visibility and purchasability separate
- 4. Price overrides per catalog
- 5. Managing Shared Catalogs programmatically
- 6. Automatic catalog assignment via plugin
- 7. Indexing: category permissions and the price index
- 8. Performance implications with many shared catalogs
- 9. Operations: maintenance and traceability
- 10. Summary
- 11. FAQ
1. Placing Shared Catalogs in a B2B context
A Shared Catalog is a named subset of the public catalog that gets assigned to one or more companies, controlling which categories and products are even visible to their members. Unlike a plain customer group price rule, a Shared Catalog therefore goes beyond pricing and additionally affects the visibility of entire categories.
In the default setup, every company is assigned to exactly one Shared Catalog, the public catalog by default, which shows every category without restriction. Once a custom Shared Catalog is created and assigned to a company, its members see only the categories released within it, regardless of what the catalog looks like for anonymous visitors or other companies.
2. Technical setup: a hidden customer group and Category Permissions
Under the hood, a Shared Catalog is not an entirely new concept but a combination of two existing mechanisms. When a Shared Catalog is created, Magento automatically generates its own customer group, hidden from administrators in the regular customer group grid, that serves internally as the link between company and catalog. That hidden group is then used exactly like a regular customer group by the category permissions functionality of the Magento_CatalogPermissions module.
For every category, a permission of ALLOW, DENY or ALLOW_PARTIAL can be stored per customer group, where ALLOW_PARTIAL shows the category in navigation but blocks the product content. A Shared Catalog sets these permissions deliberately for its hidden customer group, so categories outside the released structure remain effectively invisible for members of the assigned company, while technically still being filtered through the category permissions index.
<?php
declare(strict_types=1);
namespace Mironsoft\SharedCatalogExtension\Model;
use Magento\CatalogPermissions\App\ConfigInterface;
use Magento\CatalogPermissions\Model\Permission;
use Magento\SharedCatalog\Api\SharedCatalogRepositoryInterface;
/**
* Reads the effective category permission for a shared catalog's hidden
* customer group, used to evaluate it in a custom report.
*/
class SharedCatalogPermissionReader
{
/**
* @param SharedCatalogRepositoryInterface $sharedCatalogRepository
* @param ConfigInterface $permissionsConfig
*/
public function __construct(
private readonly SharedCatalogRepositoryInterface $sharedCatalogRepository,
private readonly ConfigInterface $permissionsConfig,
) {
}
/**
* Returns true if the given category is visible for the shared catalog.
*
* @param int $sharedCatalogId
* @param int $categoryId
* @return bool
*/
public function isCategoryVisible(int $sharedCatalogId, int $categoryId): bool
{
$sharedCatalog = $this->sharedCatalogRepository->get($sharedCatalogId);
$customerGroupId = (int) $sharedCatalog->getCustomerGroupId();
return $this->permissionsConfig->getPermission($categoryId, 0, $customerGroupId)
!== Permission::PERMISSION_DENY;
}
}
3. Keeping visibility and purchasability separate
A common misunderstanding is treating visibility and purchasability as the same mechanism. Category Permissions control exclusively whether a category or product shows up in navigation and search, not whether a product can actually be ordered. A product can be technically visible yet still not orderable through other mechanisms such as stock or minimum order quantities, and conversely a product can be made invisible through a DENY rule even though it would be orderable in terms of price and stock.
For custom extensions this means visibility checks and price checks have to be implemented separately. Anyone building a custom product feed for a Shared Catalog cannot rely solely on the category permissions index, but must also factor in the catalog's price overrides and the product's regular catalog visibility to get a consistent result.
4. Price overrides per catalog
Besides visibility, the second core function of a Shared Catalog is pricing. For every catalog, each product can have either a fixed price or a percentage or absolute deviation from the regular catalog price stored against it. Technically these overrides run through the same price rule infrastructure used for regular catalog price rules, just targeted at the hidden customer group of the given shared catalog.
For maintaining large price lists, the admin offers an export as an Excel sheet where price and visibility can be edited together per product and then re-imported. For automated price maintenance from an external ERP system, a custom import against the price rule APIs is preferable instead, using the same data path but without the manual Excel detour, and integrating into an existing price synchronization process.
5. Managing Shared Catalogs programmatically
Through Magento\SharedCatalog\Api\SharedCatalogRepositoryInterface and SharedCatalogManagementInterface, shared catalogs can be fully created, assigned categories, and linked to companies programmatically, without touching the admin manually. That matters particularly for projects where new company customers get created automatically from an external system and need a matching catalog assigned right away.
For bulk operations, such as adjusting hundreds of product prices in a catalog at once, calling the price rule services directly is considerably more efficient than hundreds of individual repository calls, because it avoids unnecessary individual transactions and repeated recalculation of the price rule.
6. Automatic catalog assignment via plugin
A typical extension case is automatically assigning a matching Shared Catalog as soon as a new company is created, for example based on a custom attribute such as customer segment or sales region. A plugin on company creation is the right fit here, checking after a successful save which shared catalog matches the stored rule and performing the assignment automatically.
It matters not to run the assignment inside the before part of a plugin, because the company ID is not yet known at that point. An after plugin on the save method is the correct approach here, since the fully saved company entity, including its ID, is available and the assignment can be performed reliably.
<?php
declare(strict_types=1);
namespace Mironsoft\SharedCatalogExtension\Plugin;
use Magento\Company\Api\CompanyRepositoryInterface;
use Magento\Company\Api\Data\CompanyInterface;
use Magento\SharedCatalog\Api\SharedCatalogManagementInterface;
use Mironsoft\SharedCatalogExtension\Model\SegmentCatalogResolver;
/**
* Automatically assigns the shared catalog matching the customer segment
* to a newly created company.
*/
class AssignCatalogOnCompanyCreatePlugin
{
/**
* @param SegmentCatalogResolver $catalogResolver
* @param SharedCatalogManagementInterface $catalogManagement
*/
public function __construct(
private readonly SegmentCatalogResolver $catalogResolver,
private readonly SharedCatalogManagementInterface $catalogManagement,
) {
}
/**
* @param CompanyRepositoryInterface $subject
* @param CompanyInterface $result
* @return CompanyInterface
*/
public function afterSave(CompanyRepositoryInterface $subject, CompanyInterface $result): CompanyInterface
{
$sharedCatalogId = $this->catalogResolver->resolveForCompany($result);
if ($sharedCatalogId !== null) {
$this->catalogManagement->assignCompany((int) $result->getId(), $sharedCatalogId);
}
return $result;
}
}
7. Indexing: category permissions and the price index
Every shared catalog internally creates its own customer group, and both the category permissions index and the product price index operate over a matrix of customer group by category, or customer group by product respectively. With every additional shared catalog that matrix grows, which directly affects the runtime of the corresponding indexers, especially on large catalogs with many categories.
In practice this means a full reindex after creating several new shared catalogs can take noticeably longer than before, because both visibility and price calculations have to run again for each additional hidden group. Anyone planning many parallel catalogs should keep the indexer mode and the available resources of the indexing cron in mind accordingly.
8. Performance implications with many shared catalogs
Past a certain number of parallel shared catalogs, in practice often somewhere in the mid double digits depending on catalog and category size, the indexing load becomes noticeable. Instead of creating a separate catalog for every single customer segment, consolidation often pays off: similar pricing strategies can frequently be covered through shared catalogs with additional, more granular price rules, instead of creating a new hidden customer group for every small deviation.
For stores with genuinely many different company customers, it is also worth deliberately scheduling the full reindex outside peak hours and using the schedule mode for the affected indexers, instead of triggering an immediate, synchronous recalculation across the entire catalog on every small price change.
9. Operations: maintenance and traceability
Since shared catalogs control both visibility and pricing, clear internal documentation of which catalog maps to which customer segment with which pricing logic pays off. Without that overview, it quickly becomes unclear as the catalog count grows which company sees which prices, especially when several catalogs have been maintained by different team members over time.
For audits and support requests, it is also worth being able to trace the underlying customer group assignment and the category permissions entries directly in the database, not just through the admin interface, particularly when a customer reports seeing, or not seeing, a product incorrectly.
| Aspect | Public catalog | Shared Catalog | Technical basis |
|---|---|---|---|
| Visibility | All categories visible | Only released categories | Category permissions per customer group |
| Pricing | Regular catalog prices | Fixed or deviating prices | Price rules on hidden customer group |
| Customer group | Standard groups | Automatically created hidden group | Generated when catalog is created |
| Assignment | No assignment needed | Exactly one catalog per company | SharedCatalogManagementInterface |
| Index load | Constant | Grows with each catalog | Customer group by category matrix |
| Maintenance | Central in the catalog | Excel export/import per catalog | SharedCatalog admin grid |
Mironsoft
Magento development, module consulting, and system architecture
A Magento project that needs a second opinion or experienced execution?
We build custom Magento modules, advise on architecture decisions, and take on complex implementations, from service contract planning to production-ready deployment.
Architecture Consulting
Have module and system architecture thought through properly before you build.
Custom Module Development
Build custom Magento modules cleanly, following best practices.
Code Review & Audit
Have existing modules reviewed for performance, security, and maintainability.
10. Summary
Shared Catalogs Pricing Strategy
Technical basis
Every shared catalog creates a hidden customer group, controlled through category permissions.
Pricing
Price overrides run through the same price rule infrastructure as regular catalog price rules.
Separation
Visibility and purchasability are separate mechanisms and must be checked separately in custom extensions.
Performance
Many parallel catalogs enlarge the indexing matrix, consolidation reduces the load noticeably.