With BC27 we got a new option to mask field values, just like we have had for a long time, but there’s a new twist. Check out the video for all the details:

In this video, Erik explores a new feature introduced in Business Central 27 (BC27): the MaskType property. This property provides a built-in way to conceal sensitive field data on screen while still allowing users to reveal it when needed — a significant improvement over the traditional ExtendedDatatype = Masked approach. Erik also demonstrates custom masking logic for scenarios where you want partial data visibility, such as showing only the last four digits of a credit card number.
The Traditional Approach: ExtendedDatatype = Masked
Before BC27, if you wanted to hide a field’s value on a page, you would use the ExtendedDatatype property set to Masked. This renders the field value as dots (or asterisks), and there is no way for the user to reveal the actual value through the UI.
Erik demonstrates this by adding a field to the Customer Card and setting:
ExtendedDatatype = Masked;
The result: the field shows dots when you type into it, and even the page inspection tool shows asterisks instead of the real value. This is ideal for data that should never be visible to the user — passwords, API keys, registration tokens, and similar secrets.
But what if the data is sensitive yet users sometimes need to see it? Previously, developers had to resort to workarounds like adding an AssistEdit trigger that displayed the value via a Message call — functional, but far from elegant.
The New Approach: MaskType = Concealed (BC27)
With BC27, Microsoft introduced a new page field property called MaskType. It accepts two values:
- None — the field behaves normally (as if the property isn’t set)
- Concealed — the field value is hidden behind dots, but with a key difference: a small eye icon (with a slash through it) appears next to the field
Clicking the eye icon reveals the actual value. Clicking it again re-conceals it. This is a built-in toggle that requires no custom code.
Key Differences from ExtendedDatatype = Masked
- The dot count differs: With
MaskType = Concealed, the number of dots displayed does not necessarily correspond to the actual character count of the value. This adds an extra layer of obfuscation — an observer can’t even deduce the length of the data. - Reveal toggle: The eye icon lets users see and then re-hide the value at will.
- Page inspection still shows the real value: Unlike
ExtendedDatatype = Masked, where page inspection also shows asterisks, theMaskType = Concealedapproach does expose the actual value in the page inspection pane. This is an important distinction to be aware of.
When to Use Which
| Scenario | Recommended Property |
|---|---|
| Passwords, API keys — never visible | ExtendedDatatype = Masked |
| Social security numbers, sensitive IDs — sometimes visible | MaskType = Concealed |
Erik notes that this feature is particularly useful in “semi-public” scenarios — for example, a point-of-sale-like setup where a Business Central screen is partially visible to bystanders and you want to protect sensitive information from shoulder surfing.
No Timeout (Yet)
Erik observes that once you click the eye icon to reveal the value, it stays visible indefinitely until you click the icon again. He suggests that an auto-hide timeout (e.g., 10 or 30 seconds) would be a welcome enhancement. For now, users need to remember to re-conceal the field manually.
Limitation: Cannot Add MaskType to Existing Fields via Page Extensions
Erik tries an interesting experiment: can you add MaskType = Concealed to an existing base application field (like the Balance field on the Customer Card) through a page extension? The answer is no. Business Central throws an error:
“Modifications to property MaskType are not allowed.”
This means you cannot retroactively conceal fields defined in the base application or other extensions. Erik argues that Microsoft should at least allow increasing the concealment level (from none to concealed), even if reducing it should be blocked. As it stands, the workaround would be to hide the original field and add your own concealed version — not ideal, but functional.
Custom Masking: Showing the Last Four Digits
For scenarios where you want more control over what’s displayed — such as showing only the last four digits of a credit card number — you can implement custom masking logic. The source code provided demonstrates this pattern:
Table Extension: Adding the Field
tableextension 50100 MyCustomer extends Customer
{
fields
{
field(50100; CreditCardNo; Text[50])
{
Caption = 'Credit Card No.';
}
}
}
This adds a CreditCardNo field to the Customer table to store the full credit card number.
Page Extension: Custom Masking Logic
pageextension 50100 MyCustomer extends "Customer Card"
{
layout
{
addafter(Name)
{
field(CreditCardCtl; MaskedCreditCard)
{
Caption = 'Credit Card No.';
ApplicationArea = all;
trigger OnValidate()
begin
if strlen(MaskedCreditCard) < 5 then
error('Not a valid credit card');
Rec.CreditCardNo := MaskedCreditCard;
MaskedCreditCard := PerformMasking();
end;
}
}
}
trigger OnAfterGetRecord()
begin
MaskedCreditCard := PerformMasking();
end;
trigger OnAfterGetCurrRecord()
begin
MaskedCreditCard := PerformMasking()
end;
procedure PerformMasking(): Text
begin
if Strlen(Rec.CreditCardNo) > 4 then
exit('*************' + Rec.CreditCardNo.Substring(strlen(Rec.CreditCardNo) - 3))
else
exit('');
end;
var
MaskedCreditCard: Text[50];
}
Here’s how this works:
- The page control is bound to a variable (
MaskedCreditCard) rather than directly to the table field. This gives you full control over what’s displayed. - The
PerformMasking()procedure replaces all but the last four characters with asterisks — a common pattern for credit card display (e.g.,*************1234). - On
OnAfterGetRecordandOnAfterGetCurrRecord, the masked version is computed and displayed. - On
OnValidate, the full value entered by the user is saved toRec.CreditCardNo, and the display is immediately re-masked. - A basic validation check ensures the input is at least 5 characters long.
This approach gives you the flexibility to define exactly how masking works — partial reveal, custom asterisk patterns, different rules for different fields — while keeping the actual sensitive data stored securely in the table field.
Summary
BC27 introduces the MaskType property as a welcome addition to the developer’s toolkit for protecting sensitive on-screen data:
ExtendedDatatype = Maskedremains the right choice for data that should never be visible (passwords, API keys).MaskType = Concealedis perfect for data that is sensitive but occasionally needs to be viewed (social security numbers, account identifiers), providing a built-in reveal/hide toggle.- Custom masking logic (as shown in the credit card example) is ideal when you want partial visibility or specific formatting rules.
- Be aware that
MaskType = Concealeddoes not hide values from page inspection, and you currently cannot apply it to existing base application fields via page extensions.
This is not about computer security in the traditional sense — it’s about physical security, protecting against shoulder surfing in environments where screens may be partially visible to unauthorized observers.