---
schema_version: "1"
id: c49929a77f21f8184f4abb9777d06c3b047789a975bb3895ca05c590664a936e
title: Implement Custom Self-Registration for a B2B Store
collection: developer
version: current
locale: en-us
portal_url: https://docs.salesforce.com/developer/current/en-us/commerce-cloud/salesforce-commerce/guides/d2c-commerce/b2b-comm-custom-self-registration.md
canonical_url: https://developer.salesforce.com/docs/commerce/salesforce-commerce/guide/b2b-comm-custom-self-registration.html
source_site: developer.salesforce.com
content_type: documentation
content_hash: 84893e2f983f4065a093cc6a744971f8f95eafb6284e126d00139164fd54690c
products:
  - B2B Commerce Developer Guide
  - Salesforce APIs
---
# Implement Custom Self-Registration for a B2B Store

Implement automated customer self-registration for Salesforce B2B Commerce storefronts using a custom Lightning Web Component and an Apex controller that orchestrates user provisioning, account creation, buyer access, and permission assignment.

The self-registration solution consists of two primary components:

- Custom web component — Provides the user-facing registration interface with form validation, user feedback, and storefront integration.
- Custom Apex controller — Orchestrates backend operations including user provisioning, account creation, buyer access configuration, and permission management.

## When to Use This Implementation

Use this implementation when you want to:

- Enable customers to register for B2B Commerce stores without administrator intervention.
- Support password-based user authentication.
- Maintain control over user provisioning and account creation workflows.
- Enforce data validation and business rules during registration.
- Automate buyer access setup and permission assignment.
- Streamline the customer onboarding experience.

## Customize the Self-Registration Page

Customize the store’s registration page using custom Lightning Web Components (LWC) and Apex code. For a sample Apex class, see the [CommerceSelfRegistrationController.cls class](#sample-implementation-of-commerceselfregistrationcontroller).

Before you begin:

- [Create a Salesforce DX Project](https://developer.salesforce.com/docs/commerce/salesforce-commerce/guide/b2b-b2c-comm-create-sample-lwc-project.html).
- [Create a sample Lightning web component](https://developer.salesforce.com/docs/commerce/salesforce-commerce/guide/b2b-b2c-comm-create-sample-lwc.html).
- [Deploy a custom component](https://developer.salesforce.com/docs/commerce/salesforce-commerce/guide/b2b-b2c-comm-deploy-lwc-component.html).

1. Add the new UI component to your store’s self-registration page.

   a. In the navigation sidebar, select a store from the **Store** dropdown.

   b. Select **Website Design**, and then click **Experience Builder**.

   c. In Experience Builder, go to the Self-registration page.

   d. To view the properties, click the page.

   e. Drag and drop the component on the page.

   f. Configure the component properties.

   g. Publish your store.

2. Grant `CommerceSelfRegistrationController.cls` access to guest users.

> **Note:** Grant guest users access only to the Apex classes required for self-registration. Don't grant access to unrelated classes or classes that expose sensitive operations.

   Don’t grant access to unrelated classes or classes that expose sensitive operations.

   a. In the navigation sidebar, select a store from the **Store** dropdown.

   b. Select **Website Design**, and then click **Experience Builder**.

   c. In Experience Builder, go to **Settings**, and then click **General**.

   d. Click the Guest User Profile.

   e. In the Enabled Apex Class Access section, click **Edit**.

   f. Add the Apex class to the list of enabled classes, and save your changes.

## Sample Implementation of `CommerceSelfRegistrationController`

The `CommerceSelfRegistrationController` class is the core backend component that handles all server-side operations for customer self-registration.

The following sample shows a `CommerceSelfRegistrationController` class implementation.

```apex
/**
 * Self-registration controller for Experience Cloud with B2B Commerce integration
 */
global without sharing class CommerceSelfRegistrationController {

    private static final String LOG_PREFIX = '[CommerceSelfReg]';

    public class RegistrationException extends Exception {}

    global class RegistrationResult {
        @AuraEnabled global Boolean success;
        @AuraEnabled global String message;
        @AuraEnabled global String redirectUrl;
    }

    /**
     * Register a new user with BuyerAccount and auto-login
     * Returns: RegistrationResult with success status, message, and redirect URL
     */
    @AuraEnabled(cacheable=false)
    global static RegistrationResult registerUserAndRedirectForLogin(
        String firstName,
        String lastName,
        String email,
        String phoneNumber,
        String password,
        String confirmPassword,
        String startUrl
    ) {
        RegistrationResult result = new RegistrationResult();
        result.success = false;

        Savepoint sp = Database.setSavepoint();

        try {
            String validationError = validateRegistrationInput(lastName, email, password, confirmPassword);
            if (validationError != null) {
                result.message = validationError;
                return result;
            }

            String permissionSetGroupId = getPermissionSetGroupIdFromNetwork();

            if (String.isBlank(startUrl)) {
                startUrl = '';
            }

            String accountId = createBusinessAccount(firstName, lastName);
            String userId = createUser(firstName, lastName, email, phoneNumber, password, accountId);

            createBuyerAccount(accountId);

            // Add buyer to all default buyer groups from config
            List<String> defaultBuyerGroupIds = getDefaultBuyerGroupsFromConfig();
            if (!defaultBuyerGroupIds.isEmpty()) {
                addBuyerToDefaultGroups(accountId, defaultBuyerGroupIds);
            }

            assignPermissionSetToUserAsync(userId, permissionSetGroupId);
            performAutoLogin(email, password, startUrl, result);

        } catch (Exception ex) {
            Database.rollback(sp);
            result.success = false;
            result.message = 'Registration error: ' + ex.getMessage();
            System.debug(LOG_PREFIX + ' Registration exception: ' + ex.getMessage());
            System.debug(LOG_PREFIX + ' Stack trace: ' + ex.getStackTraceString());
        }

        return result;
    }

    /**
     * Validate registration input fields
     * Returns: Error message if validation fails, null if valid
     */
    private static String validateRegistrationInput(String lastName, String email, String password, String confirmPassword) {
        if (String.isBlank(lastName)) {
            return 'Last name is required';
        }

        if (String.isBlank(email)) {
            return 'Email is required';
        }

        if (String.isBlank(password)) {
            return 'Password is required';
        }

        if (password != confirmPassword) {
            return 'Passwords do not match';
        }

        return null;
    }

    /**
     * Create external user using Site.createExternalUser()
     * Returns: User ID
     */
    private static String createUser(String firstName, String lastName, String email,
        String phoneNumber, String password, String accountId) {
        try {
            User u = new User();
            u.FirstName = firstName;
            u.LastName = lastName;
            u.Email = email;
            u.Username = email;
            u.CommunityNickname = generateNickname(firstName, lastName, email);
            u.EmailEncodingKey = 'UTF-8';
            u.LocaleSidKey = 'en_US';
            u.LanguageLocaleKey = 'en_US';
            u.TimeZoneSidKey = 'America/Los_Angeles';
            u.Alias = generateAlias(firstName, lastName);

            if (!String.isBlank(phoneNumber)) {
                u.Phone = phoneNumber;
            }

            String userId = Site.createExternalUser(u, accountId, password);

            if (userId == null) {
                throw new RegistrationException('Site.createExternalUser returned null - user creation failed');
            }

            System.debug(LOG_PREFIX + ' Created external user: ' + userId);
            return userId;

        } catch (Exception ex) {
            System.debug(LOG_PREFIX + ' Error creating user: ' + ex.getMessage());
            System.debug(LOG_PREFIX + ' Stack trace: ' + ex.getStackTraceString());
            throw ex;
        }
    }

    /**
     * This a sample implementation and customer's need to provider their own implementation
     * Generate unique community nickname
     * Returns: Nickname string (max 40 chars)
     */
    private static String generateNickname(String firstName, String lastName, String email) {
        String nickname = (firstName != null ? firstName : '') + (lastName != null ? lastName : '');
        if (String.isBlank(nickname)) {
            nickname = email.substringBefore('@');
        }
        nickname = nickname.replaceAll('[^a-zA-Z0-9]', '');
        nickname = nickname + String.valueOf(System.now().getTime()).substring(7);
        return nickname.substring(0, Math.min(nickname.length(), 40));
    }

    /**
     * This a sample implementation and customer's need to provider their own implementation
     * Generate user alias.
     * Returns: Alias string (max 8 chars)
     */
    private static String generateAlias(String firstName, String lastName) {
        String alias = '';
        if (firstName != null) alias += firstName.substring(0, Math.min(firstName.length(), 4));
        if (lastName != null) alias += lastName.substring(0, Math.min(lastName.length(), 4));
        if (String.isBlank(alias)) alias = 'user';
        return alias.substring(0, Math.min(alias.length(), 8));
    }

    /**
     * Perform auto-login after successful registration and update result object
     */
    private static void performAutoLogin(String email, String password, String startUrl, RegistrationResult result) {
        try {
            PageReference loginResult = Site.login(email, password, startUrl);
            if (loginResult != null) {
                result.redirectUrl = loginResult.getUrl();
                result.success = true;
                result.message = 'Registration and login successful!';
                System.debug(LOG_PREFIX + ' Auto-login successful, redirect URL: ' + result.redirectUrl);
            } else {
                result.success = true;
                result.redirectUrl = null;
                result.message = 'Registration successful but auto-login failed. Please login manually.';
                System.debug(LOG_PREFIX + ' Auto-login failed - Site.login returned null');
            }
        } catch (Exception loginEx) {
            result.success = true;
            result.redirectUrl = null;
            result.message = 'Registration successful but auto-login failed. Please login manually.';
            System.debug(LOG_PREFIX + ' Auto-login exception: ' + loginEx.getMessage());
        }
    }

    /**
     * Create a business account to be associated with registering user
     * Returns: Business account ID
     */
    private static String createBusinessAccount(String firstName, String lastName) {
        Account account = new Account();
        account.Name = firstName + ' ' + lastName;

        String recordTypeId = getDefaultAccountRecordTypeId();
        if (String.isNotBlank(recordTypeId)) {
            account.RecordTypeId = recordTypeId;
        }

        ID siteAdminId = getSiteAdminId();
        if (siteAdminId != null) {
            account.OwnerId = siteAdminId;
        }

        insert account;
        System.debug(LOG_PREFIX + ' Created business account: ' + account.Id);
        return account.Id;
    }

    /**
     * Get default account record type ID from Commerce configuration
     * Returns: Account record type ID (15 chars), or null
     */
    private static String getDefaultAccountRecordTypeId() {
        String networkId = Network.getNetworkId();

        List<CommerceConfigRelatedRecord> configs = [
            SELECT ConfigReferenceId
            FROM CommerceConfigRelatedRecord
            WHERE ContextId = :networkId
            AND ConfigUseCase = 'SelfRegistration'
            AND ConfigKey = 'AccountRecordType'
            LIMIT 1
        ];

        if (!configs.isEmpty() && String.isNotBlank(configs[0].ConfigReferenceId)) {
            String recordTypeId = configs[0].ConfigReferenceId;
            if (recordTypeId.length() == 18) {
                recordTypeId = recordTypeId.substring(0, 15);
            }
            System.debug(LOG_PREFIX + ' Found account record type ID: ' + recordTypeId);
            return recordTypeId;
        }

        return null;
    }

    /**
     * Get site admin ID
     * Returns: Site admin user ID as ID, or null
     */
    private static ID getSiteAdminId() {
        return Site.getAdminId();
    }

    /**
     * Create BuyerAccount for Commerce integration
     */
    private static void createBuyerAccount(String accountId) {
        BuyerAccount buyerAccount = new BuyerAccount(
            BuyerId = accountId,
            Name = 'Buyer-' + accountId,
            IsActive = true
        );
        insert buyerAccount;
        System.debug(LOG_PREFIX + ' Created BuyerAccount: ' + buyerAccount.Id);
    }

    /**
     * Add buyer to all default buyer groups
     */
    private static void addBuyerToDefaultGroups(String accountId, List<String> defaultBuyerGroupIds) {
        List<BuyerGroupMember> members = new List<BuyerGroupMember>();
        for (String buyerGroupId : defaultBuyerGroupIds) {
            if (String.isNotBlank(buyerGroupId)) {
                members.add(new BuyerGroupMember(
                    BuyerId = accountId,
                    BuyerGroupId = buyerGroupId
                ));
            }
        }

        if (!members.isEmpty()) {
            insert members;
            System.debug(LOG_PREFIX + ' Added account to ' + members.size() + ' default BuyerGroups');
        }
    }

    /**
     * Async wrapper to assign permission set (avoids Mixed DML)
     */
    @future
    private static void assignPermissionSetToUserAsync(String userId, String permissionSetGroupId) {
        assignPermissionSetToUser(userId, permissionSetGroupId);
    }

    /**
     * Assign permission set group to user
     */
    private static void assignPermissionSetToUser(String userId, String permissionSetGroupId) {
        PermissionSetAssignment psa = new PermissionSetAssignment(
            AssigneeId = userId,
            PermissionSetGroupId = permissionSetGroupId
        );
        insert psa;
        System.debug(LOG_PREFIX + ' Assigned permission set group to user: ' + psa.Id);
    }

    /**
     * Get permission set group ID from NetworkSelfRegistration configuration
     * Returns: Permission set group ID
     */
    private static String getPermissionSetGroupIdFromNetwork() {
        String networkId = Network.getNetworkId();
        if (String.isBlank(networkId)) {
            System.debug(LOG_PREFIX + ' No network ID found');
            throw new RegistrationException('No network ID found');
        }

        List<NetworkSelfRegistration> selfRegConfigs = [
            SELECT PermissionSetGroupId
            FROM NetworkSelfRegistration
            WHERE NetworkId = :networkId
            LIMIT 1
        ];

        if (selfRegConfigs.isEmpty() || String.isBlank(selfRegConfigs[0].PermissionSetGroupId)) {
            System.debug(LOG_PREFIX + ' No permission set group configured in NetworkSelfRegistration');
            throw new RegistrationException('No permission set group configured in NetworkSelfRegistration');
        }

        String permSetGroupId = selfRegConfigs[0].PermissionSetGroupId;
        System.debug(LOG_PREFIX + ' Found permission set group ID from NetworkSelfRegistration: ' + permSetGroupId);
        return permSetGroupId;
    }

    /**
     * Get default buyer group IDs from CommerceConfigRelatedRecord
     * This follows Salesforce's official implementation pattern
     * Returns: List of BuyerGroup IDs configured for self-registration
     */
    private static List<String> getDefaultBuyerGroupsFromConfig() {
        String networkId = Network.getNetworkId();
        List<String> buyerGroupIds = new List<String>();

        try {
            List<CommerceConfigRelatedRecord> configs = [
                SELECT ConfigReferenceId
                FROM CommerceConfigRelatedRecord
                WHERE ContextId = :networkId
                AND ConfigUseCase = 'SelfRegistration'
                AND ConfigKey = 'DefaultBuyerGroup'
            ];

            for (CommerceConfigRelatedRecord config : configs) {
                if (String.isNotBlank(config.ConfigReferenceId)) {
                    buyerGroupIds.add(config.ConfigReferenceId);
                }
            }

            System.debug(LOG_PREFIX + ' Found ' + buyerGroupIds.size() + ' default buyer groups: ' + buyerGroupIds);
        } catch (Exception e) {
            System.debug(LOG_PREFIX + ' Error retrieving buyer groups: ' + e.getMessage());
            throw new RegistrationException('Error retrieving buyer groups');
        }

        return buyerGroupIds;
    }
}
```

## See Also

- [Manage Access to a B2B Store](https://help.salesforce.com/s/articleView?id=commerce.comm_buyer_access.htm&type=5)
- [Configure Self-Registration for a B2B Store](https://help.salesforce.com/s/articleView?id=commerce.comm_self_registration.htm&type=5)
- [Website Design for B2B Stores](https://help.salesforce.com/s/articleView?id=commerce.comm_customize_template.htm&type=5)
- [Publish Your Store](https://help.salesforce.com/s/articleView?id=commerce.comm_publish_store.htm&type=5)
- [_Salesforce B2B Commerce_: Configure Self-Registration for a B2B Store](https://help.salesforce.com/s/articleView?id=commerce.comm_self_registration.htm&type=5)
- [_Salesforce B2B Commerce_: Website Design for B2B Stores](https://help.salesforce.com/s/articleView?id=commerce.comm_customize_template.htm&type=5)
- [_Salesforce B2B Commerce_: Publish Your Store](https://help.salesforce.com/s/articleView?id=commerce.comm_publish_store.htm&type=5)
