Skip to content

Getting Started

Set up your Experience Cloud site#

Public donation pages, the donor portal, and event tickets all run on an Experience Cloud (Enhanced LWR) site. Pledgivo ships every component that goes *on* that site — it doesn't create the site itself. That's a one-time manual setup you do in Salesforce Setup, not something the package installs for you.

Internal-only orgs can skip this

If you're only recording gifts staff take over the phone and never publishing a public donation page, you don't need Experience Cloud at all — skip ahead to Setup assistant.

Watch it first#

What it is. Seven and a half minutes building the site this package’s public pages run on — enabling Digital Experiences, creating and selecting the site, opening it to guests, assigning the guest permission set, granting Campaign read by hand, then publishing and activating. The last two chapters are the payoff and the catch: what an anonymous visitor actually gets on each public route, and the one checklist row the panel cannot fully verify for you.

Before you start#

Confirm your org edition supports Experience Cloud — Enterprise, Unlimited, Performance, or Developer. Professional edition can't publish public pages; see Installation.

1. Enable Digital Experiences#

Setup → Digital Experiences → Settings → Enable Digital Experiences.

Until you tick this, Digital Experiences does not appear in Setup at all — there is no All Sites list and nothing to create. Salesforce asks you to choose an Enhanced Domain subdomain as part of switching it on; that name becomes part of every public donation URL, is org-wide, and cannot be undone, so pick one you are happy to publish.

The Settings console's Site & Domain panel is a seven-step checklist that starts with this same step, machine-checks it against your org, and links you straight to the Setup page.

2. Create the site#

Setup → Digital Experiences → All Sites → New.

  1. Choose the Build Your Own (LWR) template.
  2. Name the site (e.g. "Giving" or your org's name). Salesforce derives the URL prefix from this name — if it appends a suffix like vforcesite because your preferred prefix was already reserved elsewhere, you can change it afterward under Experience Builder → Settings → URL & Access.
  3. Click Create. Site creation runs as a background job and can take several minutes.

All Sites renders an empty pane

On some orgs the All Sites screen loads its shell — breadcrumb, heading — and then shows nothing at all: no site table, no New button. A hard reload does not fix it. It is the same blank-shell behaviour the Lightning Permission Sets page sometimes shows, and it has nothing to do with this package; it simply blocks the documented path.

Create the site from the CLI instead — it produces exactly the same site:

sf community create --name "Giving" --template-name "Build Your Own (LWR)" \
  --url-path-prefix giving --target-org <your-org-alias>

Creation is asynchronous either way. Confirm it landed with:

sf data query --query "SELECT Name, Status, UrlPathPrefix FROM Network" --target-org <your-org-alias>

Read the prefix back rather than assuming it. Salesforce may return something other than what you asked for — giving came back as givingvforcesite on a first-ever site in a completely clean org, not only when the prefix was already taken. Never hardcode the prefix anywhere; take it from that query.

Once the site exists, open the Settings console's Experience Cloud → Site & Domain panel, pick it in the Create or choose your site step, and click Use this site — that writes the site's address into Settings as the Experience Site URL.

This URL is the only source of every donor-portal link

The sign-in email, the "Manage your giving" links on the public pages, and the link a staff member sends from a donor record are all built from this one value. Until it is set, the public sign-in form accepts an email and sends nothing — the reason is recorded in Diagnostic Logs — and the staff "Send portal link" action is disabled with the same message. Paste the address of the LWR site (the one ending in the URL prefix you chose, e.g. /fundraising), never the companion Visualforce site that Salesforce creates alongside it.

3. Build the Donate page#

Campaigns, fundraiser pages, team pages, and event registration all share one page and one component — Public Fundraising Experience. It reads the campaign's record type, subtype, and URL slug to decide what to render, so you only build this once regardless of how many campaign types you run.

  1. Open the site in Experience Builder.
  2. Pages → New Page → Standard → Flexible Layout.
  3. Name it (e.g. "Donate") and, in Page Properties, set its URL — e.g. donate.
  4. Drag the Public Fundraising Experience component into the content region and Save.

A campaign's public link then looks like https://<your-site-domain>/donate?slug=<the campaign's public URL>.

Component missing from the palette?

Publish the site and hard-refresh Experience Builder — a newly-installed component sometimes doesn't show up until the org's cache picks up the change.

The red warning on the component is Salesforce boilerplate

Experience Builder shows a red notice on every custom component from any managed package, warning that a third-party component may not be safe under Strict CSP or Lightning Web Security. It is generic text, shown before Salesforce has looked at the component at all — it is not a finding about this package. Every component this app ships is built and tested with Strict CSP and Lightning Web Security on, which is how the public pages are expected to run. Drag it in and carry on.

Built the Donate page at a URL other than donate?

Set Donation page path to match, in the Settings console: General → Organization & Donations → Gift rules. The Campaign Gallery's donate links, the embed widget's checkout handoff, and the Fundraisers console's public-links panel all build their URLs from this setting — it defaults to /donate, so leaving it blank while your page lives somewhere else silently breaks every one of those links with a 404. Leave it blank if you used the default donate path above.

4. Build the other pages you need#

Each of these pages is independently optional, but other pages link to them by URL — using a different path than the one listed breaks that link with a 404. Build only the ones your rollout actually uses:

Page URL Component Needed for
Home / Campaign Gallery A public campaign directory — many sites already have a Home page, in which case just add the component to it
Thank you thank-you Thank You Event checkout — the buyer is sent here immediately after a successful charge
Receipt receipt Donation Receipt Anyone you email a receipt link to — build this if you send receipts at all
Donor portal donor Donor Dashboard The donor self-service portal, where returning donors sign in with an emailed code — see Publish a donor portal page
Tickets tickets Event Tickets Event ticketing. The Donor Dashboard links here on every event order — skipping this page breaks that link even if you don't otherwise use the Tickets page directly

thank-you, receipt and tickets are fixed paths — build them exactly as written. donate and donor are configurable in the Settings console under General → Organization & Donations and General → Email & Receipts. The Site & Domain panel's Build each public page step shows the paths your org is actually configured with, plus a live link to each page so you can confirm it loads.

Build each the same way as the Donate page: New Page → Standard → Flexible Layout, set the URL in Page Properties, drag in the named component, Save.

Delete the template's placeholder from Home before you publish

"Build Your Own (LWR)" seeds the Home page with a stock HTML Editor component reading "Start Building Your Page — Drag and drop a component into the content slots." Dropping the Campaign Gallery onto Home does not replace it: the placeholder stays, sits above your gallery, and publishes to donors as the first thing they see. It is easy to miss because it looks like Builder chrome rather than page content.

It also cannot be selected by clicking it on the canvas the way a component you dropped can. Delete it through the rail instead:

  1. In Experience Builder, open Page Structure (the layers icon in the left toolbar).
  2. Expand the Home page's content region and select the HTML Editor entry.
  3. Click the delete (trash) icon and confirm the Delete component? dialog.
  4. Save, then publish.

Do this on every page you build from the template, not only Home — each new Flexible Layout page gets its own copy.

Replace the site's \"Invalid Page\" message

Every LWR site already has an Error page: the site shows it for any URL that matches no page, such as a mistyped campaign link, a removed page or an old bookmark. Out of the box it is one line of text reading "Invalid Page", with no way back into the site. The package ships a branded Page Not Found component to use in its place. Installing the package can't put it there for you, because Salesforce does not package site pages:

  1. In Experience Builder, open the page menu at the top and choose Error.
  2. Select the "Invalid Page" text on the canvas and delete it.
  3. Drag Page Not Found into the empty content region.
  4. Save, then publish.

The component links donors to your open fundraisers and to the donor portal. If your portal page is not at donor, set Donor portal page path in the component's properties. Leave that property blank to hide both portal links.

Thank you is not optional if you sell tickets

Event checkout navigates to thank-you right after the charge succeeds. An org that skipped this page takes the buyer's money and lands them on a 404 — the failure happens after payment, so nothing earlier in your testing catches it.

Remove the template's empty header and footer sections

"Build Your Own (LWR)" ships its theme layout with an empty Theme Header and an empty Theme Footer region, and each one still renders a layout section — which brings 16px of padding above and below itself. The result is a 32px grey band across the top and bottom of every public page: the donation page's trust bar starts a band's width down the window instead of meeting its top edge, and the contact footer floats off the bottom.

Nothing on the page itself causes it, so it survives every page-level change you make. Remove the two sections once and it is fixed for the whole site:

  1. In Experience Builder, open the Theme panel (the paintbrush icon) and confirm your pages use the Scoped Header and Footer layout.
  2. Open Page Structure (the layers icon) and expand the Theme Header region.
  3. Select its Section entry and delete it. Do the same in Theme Footer.
  4. Save, then publish.

Only do this while the regions are genuinely empty. If you later drop a real site header or footer into either region, the section comes back with it — and that spacing is then yours, not the template's.

5. Activate guest access#

Setup → Digital Experiences → All Sites, then click Workspaces next to your site → Builder → Settings → General. Enable Public Access — without it, every visitor gets a login page instead of your donation form, no matter what permission sets are assigned below. Salesforce exposes no API to read this toggle back, so you're confirming it yourself; the Site & Domain panel marks this step Can't verify for the same reason, not because anything is wrong.

Then assign Fundraising_GuestDonor to that site's guest user. Finding the guest user is the awkward part, so follow this route exactly — you will come back to it twice more below:

  1. From that same Builder → Settings → General screen, click the link under Guest User Profile.
  2. On the profile, click View Users. Exactly one user is listed — "<your site> Site Guest User".
  3. Open that user → Permission Set Assignments → Edit Assignments → move Fundraising Guest Donor from Available to Enabled → Save. This screen is a plain two-list picker with no filters on it; if you are instead creating a permission set for the guest user, the licence rule that applies there is in After you install.

Two routes that look right and are not: Administration → Members assigns profiles and permission sets that may be members of the site, not permission sets to the guest user; and the guest user does not appear under Setup → Users at all, nor in Manage Assignments on the permission set itself. Without this assignment, guest visitors can view campaign pages but the donation form cannot submit — see Installation.

Next, grant that Guest User Read on the standard Campaign object. Fundraisers are Campaign records, and Salesforce does not let a managed package ship permissions on standard objects — they are removed when the package version is built — so Fundraising_GuestDonor carries every custom object and field grant your public pages need and can never carry this one. Without it a visitor gets an error on every campaign, donation and ticket page.

Build it as a permission set — the same screen in every org, and the one figure gs-38 shows:

  1. Setup → Permission Sets → New. Label it Guest Campaign Read (any name works; this one matches the screenshots). Leave License as --None-- — a set created under a specific user licence refuses to go onto a guest user, and the error does not mention the licence.
  2. Object Settings → Campaigns → Edit → tick Read — and nothing else — → Save.
  3. Assign it from the guest user's own record, by the Guest User Profile → View Users route above: Permission Set Assignments → Edit Assignments → move Guest Campaign Read to Enabled → Save. Manage Assignments on the permission set does not list a site guest user.

A guest user must never hold Create, Edit or Delete on Campaign. If you have already built the donor credential set in Connecting Stripe, you may add this grant to that set instead of creating a second one; the Site & Domain check reads the grant, not the set. This one is machine-checked: the Site & Domain panel's Give the guest user read access to Campaign step reads the grant back and reports Done or Pending.

Finally, grant the public Stripe credential to that same Guest User — the same Builder → Settings → General → Guest User Profile → View Users route as above. Salesforce does not let a managed permission set grant access to an external credential principal, so this package can never ship that grant — you create your own permission set (name it whatever you like) holding that credential's principal and assign it to the guest user as well as to your fundraising staff. Keep the admin credential's grant on a separate permission set that the guest user is never assigned: it carries the full secret key, so a guest user holding it can issue refunds. Unlike the Public Access toggle above, this one is machine-checked: the un-numbered guest-credential row at the foot of the Site & Domain panel reads the grant back via SetupEntityAccess and reports Done once a permission set granting the donor credential's principal is assigned to the site's guest user, or Pending with the specific reason (no grant found at all vs. granted but not assigned to this guest user) otherwise. That row grades the donor credential only — on the Payments panel, Let your public site use the credential names the exact permission sets your guest user holds so you can confirm none of them is the admin one, and Prove the donor key is restricted catches the same exposure from the other side by proving the key a guest can reach cannot issue a refund. (Prove the admin key is restricted does the same for the back-office key, which no guest can reach — that one is about limiting the blast radius if the key ever leaks, not about guest exposure.) Full walkthrough: Grant the Stripe credential.

6. Publish, then activate#

These are two separate actions on two separate screens, and you need both. Publishing without activating is the single most common reason a donation link 404s for donors while working perfectly for you.

Publish. Click Publish in Experience Builder (top-right). This is a separate step from saving your pages — nothing you build in Builder is visible to guest users until you publish.

Activate. Setup → Digital Experiences → All Sites → Workspaces beside your site → Administration → Settings → Activate. Only this moves the site's status from Preview (UnderConstruction) to Live.

Workspaces won't load? Activate from the CLI

On some orgs Experience Workspaces fails to initialise and never renders — a spinner, an Aura init error, or a blank pane. This compounds the empty All Sites list described in §2, because reaching the site through Workspaces is the documented way around that: when both fail there is no working UI route to activate at all. Neither is caused by this package, and neither produces an error message worth searching for.

There is no sf command that activates a site, but the Metadata API does it. Retrieve the Network, flip its status, and deploy it back:

# 1. Retrieve the site's Network metadata (use the site NAME, not its URL prefix)
sf project retrieve start --metadata Network:Giving --target-org <your-org-alias>

# 2. Flip the status to Live (the file lands under force-app/main/default/networks/)
perl -pi -e 's{<status>UnderConstruction</status>}{<status>Live</status>}' \
  force-app/main/default/networks/Giving.network-meta.xml

# 3. Deploy it back
sf project deploy start --metadata Network:Giving --target-org <your-org-alias>

Retrieve first rather than hand-writing the file — Network carries required fields whose values are yours, and a hand-authored file will fail to deploy. Confirm it took:

sf data query --query "SELECT Name, Status FROM Network" --target-org <your-org-alias>

Status reads Live when activation succeeded. Activating this way sends the same member welcome emails the button does.

Publishing does not activate

Experience Builder will report Published with a live URL on a site the public still cannot reach. Builder has no Activate control at all — the button is in Workspaces, and the Settings console's Site & Domain and Get Started panels are both graded on the activation status, not on whether you have published. A successful publish leaves both rows amber until you activate.

Publish again after every future change

A metadata deploy alone does not update the live site — a package upgrade or a Settings change to page composition still needs an explicit Publish to go live. Hard-reload the page after publishing before you verify anything — a cached bundle can make a successful publish look like it didn't take effect. Activation, once done, stays done.

Next#