Drupal is a registered trademark of Dries Buytaert
cms 2.1.3 Update released for Drupal core (2.1.3)! drupal 10.5.11 Update released for Drupal core (10.5.11)! drupal 11.3.11 Update released for Drupal core (11.3.11)! drupal 11.2.13 Update released for Drupal core (11.2.13)! drupal 10.6.10 Update released for Drupal core (10.6.10)! cms 2.1.2 Update released for Drupal core (2.1.2)! drupal 11.1.10 Update released for Drupal core (11.1.10)! drupal 10.5.10 Update released for Drupal core (10.5.10)! drupal 10.4.10 Update released for Drupal core (10.4.10)! drupal 11.2.12 Update released for Drupal core (11.2.12)! drupal 11.3.10 Update released for Drupal core (11.3.10)! drupal 10.6.9 Update released for Drupal core (10.6.9)! drupal 10.6.8 Update released for Drupal core (10.6.8)! drupal 11.3.9 Update released for Drupal core (11.3.9)! drupal 11.3.8 Update released for Drupal core (11.3.8)! drupal 11.3.7 Update released for Drupal core (11.3.7)! drupal 11.2.11 Update released for Drupal core (11.2.11)! drupal 10.6.7 Update released for Drupal core (10.6.7)! drupal 10.5.9 Update released for Drupal core (10.5.9)! cms 2.1.1 Update released for Drupal core (2.1.1)!

masked_output

9 sites Security covered
View on drupal.org

Masked Output

Masked Output provides configurable field formatters, a JSON:API normalizer,
and a Views field handler that mask sensitive field values across every Drupal
output surface — entity displays, REST/JSON:API responses, and Views pages —
with role-based bypass, permissioned on-demand reveal, and a full audit trail.

Ideal for displaying:

  • Payment card numbers & account IDs
  • Phone numbers and SSNs
  • Email addresses in public listings
  • API keys, tokens, and reference codes
  • Any sensitive string or telephone field

Formatters

Mask Output (string fields)

  • Show last / first N characters, mask the rest
  • Mask first / last N characters, show the rest
  • Custom mask symbol (default *)
  • Multibyte-safe

Mask Email Output (email fields)

  • Masks the local-part of an email address, preserves the domain
  • Example: [email protected]********@example.com

Mask Pattern Output (string & telephone fields)

  • Positional pattern: # = show original character,
    * = mask, any other character = literal separator
  • (***) ***-####(***) ***-5309
  • ####-****-****-####4111-****-****-1234
  • ***-**-####***-**-6789

Role-Based Bypass

Each formatter exposes a Roles that see unmasked values setting.
Users with any selected role see the original value. Bypass is enforced
identically on entity pages, Views, and JSON:API responses. The
user.roles render cache context is applied automatically to
prevent cross-user cache poisoning.

Reveal On Demand

Enable the Reveal on demand formatter option to show a
Reveal button next to each masked value. Users with the
Reveal masked output values permission can click it to see the
original value in-place. An optional Auto re-mask timeout
automatically hides the value after N seconds. Every reveal is written to
the audit log.

JSON:API Integration

When a field's default view display uses any masked formatter, the same
masking is applied automatically to JSON:API responses — no extra
configuration needed. Role bypass is honoured for authenticated consumers.
The normalizer is registered only when the jsonapi module is
enabled.

Views Integration

Every string, email, and telephone
configurable field gains a (Masked) variant in the Views
field picker. Masking strategy, character count, pattern, mask symbol, and
bypass roles are all configurable per Views field instance, independently
of the entity display formatter.

Audit Logging & Events

  • All masking operations and every reveal action are logged to the
    masked_output watchdog channel (visible at
    Reports > Recent log messages).
  • Dispatches masked_output.post_mask
    (MaskedOutputEvent) after each masking operation — event
    subscribers can override the masked value.
  • hook_masked_output_alter(&$masked, $original, $context)
    for procedural extensibility.

Developer API

  • Plugin-based strategy system — register custom mask
    strategies by annotating a class with #[MaskStrategy(...)]
    in Plugin/MaskStrategy/.
  • MaskingServiceInterface — inject and call
    maskString(), maskEmail(),
    maskPattern() programmatically.
  • See masked_output.api.php for the full hook and event reference.

Technical Highlights

  • Service-based architecture with full dependency injection
  • 69 tests / 246 assertions (Unit + Kernel)
  • PHPStan level 6 — 0 errors
  • PHPCS Drupal + DrupalPractice — 0 errors
  • Drupal 10 and 11 tested; Drupal 13 forward-compatible

Installation

composer require drupal/masked_output:^2.1

Activity

Total releases
5
First release
Feb 2025
Latest release
4 days ago
Release cadence
116 days
Stability
100% stable

Release Timeline

Releases

Version Type Release date
2.1.0 Stable May 29, 2026
2.0.3 Stable Feb 14, 2026
2.0.2 Stable Feb 22, 2025
2.0.1 Stable Feb 22, 2025
2.0.0 Stable Feb 20, 2025