Setting Up: Visualforce Page or Lightning Web Component for Salesforce

  • Updated

As an alternative to the Sendoso Chrome extension, you can add a Lightning Web Component or a Visualforce page (SFDC Lightning) to complete one-to-one sends. LWC or Visualforce page can be placed on any object; however, Sendoso recommends putting it on the lead and contact objects to pull in recipient information.

**Note - You will need Salesforce admin permissions to complete this setup

Salesforce Visualforce page Setup

To get started, go to ‘Setup’ and find Visualforce Pages.

Create a new Visualforce page.

Name it ‘Sendoso’ or ‘Gifting’, make sure to include lead or contact in the name, depending on the object you want to add this to.

Check the box to make available for lightning experiences, experience builder sites, and the mobile app.

Copy the code block for either the lead or contact:

Code Block for Contact Object: 

<apex:page standardController="Contact" showHeader="false" sidebar="false">
    <style>
        @import url('https://fonts.googleapis.com/css2?family=Roboto:wght@400;500&amp;display=swap');
        html, body { height: 100%; margin: 0; padding: 0; overflow: hidden; }
        body { font-family: 'Roboto', sans-serif; background: #ffffff; }
        #tabBar { display: flex; gap: 1rem; padding: 0 16px; border-bottom: 1px solid #e5e7eb; background: #ffffff; }
        .customTab { font-family: 'Roboto', sans-serif; font-size: 14px; font-weight: 500; color: #323C50; padding: 10px 4px; margin-bottom: -1px; cursor: pointer; border: none; background: none; outline: none; -webkit-font-smoothing: antialiased; text-decoration: none; }
        .customTab.active { text-decoration: underline; text-decoration-color: #F37021; text-decoration-thickness: 2px; text-underline-offset: 8px; }
        .customTab:hover:not(.active) { text-decoration: underline; text-decoration-color: #F37021; text-decoration-thickness: 2px; text-underline-offset: 8px; }
        .tabContent { display: none; }
        .tabContent.active { display: block; }
        iframe { display: block; width: 100%; height: calc(100vh - 42px); border: none; }
        .smartsend-container { overflow: hidden; height: calc(100vh - 42px); }
        #smartSendIframe { transform: scale(0.82); transform-origin: top left; width: calc(100% / 0.82); height: calc((100vh - 42px + 80px) / 0.82); margin-top: -52px; }
        .marketplace-container { overflow: hidden; height: calc(100vh - 42px); }
        #marketplaceIframe { transform: scale(0.82); transform-origin: top left; width: calc(100% / 0.82); height: calc((100vh - 42px + 80px) / 0.82); margin-top: -52px; }
        .dashboard-container { overflow: hidden; height: calc(100vh - 42px); }
        #dashboardIframe { transform: scale(0.75); transform-origin: top left; width: calc(100% / 0.75); height: calc((100vh - 42px + 70px) / 0.75); border: none; margin-top: -52px; }
    </style>
    <script>
        function showTab(tabName, el) {
            document.querySelectorAll('.tabContent').forEach(function(tab) { tab.classList.remove('active'); });
            document.querySelectorAll('.customTab').forEach(function(tab) { tab.classList.remove('active'); });
            document.getElementById('tab-' + tabName).classList.add('active');
            el.classList.add('active');
        }
        window.addEventListener('load', function() {
            var email = '{!JSENCODE(Contact.Email)}';
            var firstName = '{!JSENCODE(Contact.FirstName)}';
            var lastName = '{!JSENCODE(Contact.LastName)}';
            var fullName = '{!JSENCODE(Contact.Name)}';
            var street = '{!JSENCODE(Contact.MailingStreet)}';
            var city = '{!JSENCODE(Contact.MailingCity)}';
            var state = '{!JSENCODE(Contact.MailingState)}';
            var zip = '{!JSENCODE(Contact.MailingPostalCode)}';
            var country = '{!JSENCODE(Contact.MailingCountry)}';
            if (!firstName && fullName) {
                var parts = fullName.trim().split(' ');
                firstName = parts[0] || '';
                lastName = parts.slice(1).join(' ') || '';
            }
            var d = btoa(JSON.stringify({ e: email }));
            var ss = btoa(JSON.stringify({ e: email, fn: firstName, ln: lastName }));
            document.getElementById('smartSendIframe').src =
                'https://app.sendoso.com/m/send/smartsend?d=' + encodeURIComponent(d);
            document.getElementById('marketplaceIframe').src =
                'https://app.sendoso.com/m/manage/marketplace/readonly' +
                '?recipientEmail=' + encodeURIComponent(email) +
                '&recipientFirstName=' + encodeURIComponent(firstName) +
                '&recipientLastName=' + encodeURIComponent(lastName) +
                '&recipientAddress=' + encodeURIComponent(street) +
                '&recipientCity=' + encodeURIComponent(city) +
                '&recipientState=' + encodeURIComponent(state) +
                '&recipientZip=' + encodeURIComponent(zip) +
                '&recipientCountry=' + encodeURIComponent(country) +
                '&ss=' + encodeURIComponent(ss);
        });
    </script>
    <div id="tabBar">
        <button class="customTab active" onclick="showTab('sends', this)">Send</button>
        <button class="customTab" onclick="showTab('smartsend', this)">SmartSend</button>
        <button class="customTab" onclick="showTab('marketplace', this)">Marketplace</button>
        <button class="customTab" onclick="showTab('dashboard', this)">Dashboard</button>
    </div>
    <div id="tab-sends" class="tabContent active">
        <iframe src="https://app.sendoso.com/v2/plugin/sends?channel=salesforce&name={!URLENCODE(Contact.Name)}&email={!URLENCODE(Contact.Email)}&company_name={!URLENCODE(Contact.Account.Name)}&address={!URLENCODE(Contact.MailingStreet)}&city={!URLENCODE(Contact.MailingCity)}&state={!URLENCODE(Contact.MailingState)}&zip={!URLENCODE(Contact.MailingPostalCode)}&country={!URLENCODE(Contact.MailingCountry)}" scrolling="auto"></iframe>
    </div>
    <div id="tab-smartsend" class="tabContent">
        <div class="smartsend-container">
            <iframe id="smartSendIframe" src="" scrolling="auto"></iframe>
        </div>
    </div>
    <div id="tab-marketplace" class="tabContent">
        <div class="marketplace-container">
            <iframe id="marketplaceIframe" src="" scrolling="auto"></iframe>
        </div>
    </div>
    <div id="tab-dashboard" class="tabContent">
        <div class="dashboard-container">
            <iframe id="dashboardIframe" src="https://app.sendoso.com/m/dashboard" scrolling="auto"></iframe>
        </div>
    </div>
</apex:page>

Code Block for Lead Object:

<apex:page standardController="Lead" showHeader="false" sidebar="false">
    <style>
        @import url('https://fonts.googleapis.com/css2?family=Roboto:wght@400;500&amp;display=swap');
        html, body { height: 100%; margin: 0; padding: 0; overflow: hidden; }
        body { font-family: 'Roboto', sans-serif; background: #ffffff; }
        #tabBar { display: flex; gap: 1rem; padding: 0 16px; border-bottom: 1px solid #e5e7eb; background: #ffffff; }
        .customTab { font-family: 'Roboto', sans-serif; font-size: 14px; font-weight: 500; color: #323C50; padding: 10px 4px; margin-bottom: -1px; cursor: pointer; border: none; background: none; outline: none; -webkit-font-smoothing: antialiased; text-decoration: none; }
        .customTab.active { text-decoration: underline; text-decoration-color: #F37021; text-decoration-thickness: 2px; text-underline-offset: 8px; }
        .customTab:hover:not(.active) { text-decoration: underline; text-decoration-color: #F37021; text-decoration-thickness: 2px; text-underline-offset: 8px; }
        .tabContent { display: none; }
        .tabContent.active { display: block; }
        iframe { display: block; width: 100%; height: calc(100vh - 42px); border: none; }
        .smartsend-container { overflow: hidden; height: calc(100vh - 42px); }
        #smartSendIframe { transform: scale(0.82); transform-origin: top left; width: calc(100% / 0.82); height: calc((100vh - 42px + 80px) / 0.82); margin-top: -52px; }
        .marketplace-container { overflow: hidden; height: calc(100vh - 42px); }
        #marketplaceIframe { transform: scale(0.82); transform-origin: top left; width: calc(100% / 0.82); height: calc((100vh - 42px + 80px) / 0.82); margin-top: -52px; }
        .dashboard-container { overflow: hidden; height: calc(100vh - 42px); }
        #dashboardIframe { transform: scale(0.75); transform-origin: top left; width: calc(100% / 0.75); height: calc((100vh - 42px + 70px) / 0.75); border: none; margin-top: -52px; }
    </style>
    <script>
        function showTab(tabName, el) {
            document.querySelectorAll('.tabContent').forEach(function(tab) { tab.classList.remove('active'); });
            document.querySelectorAll('.customTab').forEach(function(tab) { tab.classList.remove('active'); });
            document.getElementById('tab-' + tabName).classList.add('active');
            el.classList.add('active');
        }
        window.addEventListener('load', function() {
            var email = '{!JSENCODE(Lead.Email)}';
            var firstName = '{!JSENCODE(Lead.FirstName)}';
            var lastName = '{!JSENCODE(Lead.LastName)}';
            var fullName = '{!JSENCODE(Lead.Name)}';
            var street = '{!JSENCODE(Lead.Street)}';
            var city = '{!JSENCODE(Lead.City)}';
            var state = '{!JSENCODE(Lead.State)}';
            var zip = '{!JSENCODE(Lead.PostalCode)}';
            var country = '{!JSENCODE(Lead.Country)}';
            if (!firstName && fullName) {
                var parts = fullName.trim().split(' ');
                firstName = parts[0] || '';
                lastName = parts.slice(1).join(' ') || '';
            }
            var d = btoa(JSON.stringify({ e: email }));
            var ss = btoa(JSON.stringify({ e: email, fn: firstName, ln: lastName }));
            document.getElementById('smartSendIframe').src =
                'https://app.sendoso.com/m/send/smartsend?d=' + encodeURIComponent(d);
            document.getElementById('marketplaceIframe').src =
                'https://app.sendoso.com/m/manage/marketplace/readonly' +
                '?recipientEmail=' + encodeURIComponent(email) +
                '&recipientFirstName=' + encodeURIComponent(firstName) +
                '&recipientLastName=' + encodeURIComponent(lastName) +
                '&recipientAddress=' + encodeURIComponent(street) +
                '&recipientCity=' + encodeURIComponent(city) +
                '&recipientState=' + encodeURIComponent(state) +
                '&recipientZip=' + encodeURIComponent(zip) +
                '&recipientCountry=' + encodeURIComponent(country) +
                '&ss=' + encodeURIComponent(ss);
        });
    </script>
    <div id="tabBar">
        <button class="customTab active" onclick="showTab('sends', this)">Send</button>
        <button class="customTab" onclick="showTab('smartsend', this)">SmartSend</button>
        <button class="customTab" onclick="showTab('marketplace', this)">Marketplace</button>
        <button class="customTab" onclick="showTab('dashboard', this)">Dashboard</button>
    </div>
    <div id="tab-sends" class="tabContent active">
        <iframe src="https://app.sendoso.com/v2/plugin/sends?channel=salesforce&name={!URLENCODE(Lead.Name)}&email={!URLENCODE(Lead.Email)}&company_name={!URLENCODE(Lead.Company)}&address={!URLENCODE(Lead.Street)}&city={!URLENCODE(Lead.City)}&state={!URLENCODE(Lead.State)}&zip={!URLENCODE(Lead.PostalCode)}&country={!URLENCODE(Lead.Country)}" scrolling="auto"></iframe>
    </div>
    <div id="tab-smartsend" class="tabContent">
        <div class="smartsend-container">
            <iframe id="smartSendIframe" src="" scrolling="auto"></iframe>
        </div>
    </div>
    <div id="tab-marketplace" class="tabContent">
        <div class="marketplace-container">
            <iframe id="marketplaceIframe" src="" scrolling="auto"></iframe>
        </div>
    </div>
    <div id="tab-dashboard" class="tabContent">
        <div class="dashboard-container">
            <iframe id="dashboardIframe" src="https://app.sendoso.com/m/dashboard" scrolling="auto"></iframe>
        </div>
    </div>
</apex:page>

It should look something like this once done: 

Lead

Screenshot 2025-09-09 at 10.02.35 AM.png

Contact

Screenshot 2025-09-08 at 3.23.57 PM.png

Next, navigate to the ‘Lightning App Builder’ and add a ‘New’ Lightning page:

Screenshot 2025-09-09 at 2.39.40 PM.png

Give your page a label and choose either the contact or lead object to add to:

Screenshot 2025-09-10 at 10.20.00 AM.png

Choose your page view either by cloning from an existing view or by choosing a page template. We recommend cloning from an SFDC existing page:

Screenshot 2025-09-10 at 10.20.47 AM.png

Add a tab to the page layout on the right-hand side and name it ‘Sendoso’ or ‘Send a Gift’:

Screenshot 2025-09-10 at 10.21.22 AM.png

You can also add a component to the left or right columns if preferred.

Screenshot 2025-09-10 at 8.56.55 AM.png

Add the ‘Visualforce’ component to the ‘Sendoso’ tab you created and set the height. Recommended height would be 600 px.

You can also adjust the height of the Sendoso window from the code block shown above.

Once added, assign the page to the specific profile(s) as needed:

Screenshot 2025-09-10 at 10.22.48 AM.png

And that’s it! Now on the Lead or Contact object, the necessary users should see the Sendoso tab and will be able to send directly from that tab. 

Final version will look like this on the contact or lead object once complete:

Screenshot 2025-09-10 at 10.23.38 AM.png


Salesforce Lightning Component Setup

This guide walks through installing the Sendoso Tabs component in your Salesforce org entirely through your browser — no software installs or command line needed. The component adds a tabbed Sendoso panel (Send, SmartSend, Marketplace, Dashboard) directly on Contact and Lead record pages, pre-populated with the record's information.

Deploy the Component via Workbench

Workbench is a free, browser-based tool provided by Salesforce for deploying components.

Step 1 - Open Workbench

Go to https://workbench.developerforce.com and login to Salesforce

Screenshot 2026-04-16 at 2.13.41 PM.png

Click Deploy under the Migration tab at the top of the page. Upload the zip file attached to the bottom of this article named sendoso-lwc-deply.zip

Screenshot 2026-04-16 at 2.21.44 PM.png

Click Next at the bottom and then click Deploy at the bottom of the next page.

After a few seconds, you should see a confirmation page letting you know that it was successful.

Screenshot 2026-04-16 at 2.12.07 PM.png

⚠️  Note: If you see an error about an existing Aura bundle: Go to Salesforce Setup → Lightning Components → find and delete any component named sendosoTabs, then repeat Step 2.

Configure Salesforce Settings

Click here to see a step-by-step tutorial.

Step 2 - Add Trusted URLs

This step allows the Sendoso iframes to load inside Salesforce. 

  1. In Salesforce, click the gear icon (top right) → Setup
  2. In the Quick Find search box (top left), type Trusted URLs and click it
  3. Click New Trusted URL — fill in the details below and click Save. Repeat 3 times:
Field Entry 1 — Sendoso App Entry 2 — Google Fonts API Entry 3 — Google Fonts Static
API Name Sendoso_App Google_Fonts_API Google_Fonts_Static
URL https://app.sendoso.com https://fonts.googleapis.com https://fonts.gstatic.com
Active ✅ Checked ✅ Checked ✅ Checked
CSP Context All All All
CSP Directives

connect-src

frame-src

img-src

font-src

style-src

font-src

Add the Component to Record Pages

Step 3 - Add to Contact Record Pages

  1. Open any Contact record in Salesforce
  2. Click the gear icon (top right of the record page) → Edit Page
  3. In the left panel, scroll down to find sendosoTabs under custom components
  4. Drag the sendosoTabs component onto the page where you want it to appear
  5. Click Save (top right of the App Builder)
  6. Click Activate
  7. Select Assign as Org Default → click Save

Step 4 - Add to Lead Record Pages

  1. Open any Lead record in Salesforce
  2. Repeat steps 2–7 from Step 4 above

Tutorial

Check out the above steps in tutorial format!

 

Verify Everything Works

Open any Contact or Lead page, click the Sendoso tab and see all of the Sendoso tabs there! Here's what you should see:

sendosotabs.gif

Troubleshooting

Problem Solution
Grey screen / "Content is blocked" Edit each Trusted URL in Setup and make sure the correct CSP directives are checked (see Step 3)
Component not showing in App Builder Confirm the Workbench deploy succeeded with no errors (Step 2)
Workbench deploy fails with "Aura bundle" error Go to Setup → Lightning Components → delete sendosoTabs → redeploy
Workbench shows "Invalid session" Your Salesforce session timed out — go back to Step 1 and log in again
Marketplace tab shows grey screen Contact your Sendoso representative — a feature flag may need to be enabled for your team
SmartSend tab shows grey screen Contact your Sendoso representative — a feature flag may need to be enabled for your team

Was this article helpful?

0 out of 1 found this helpful

Have feedback about this article? Click here to share your thoughts.