From clicking Publish to multi-environment deployments, custom domains, and zero-to-live disaster operations. Everything you need to get your app into users' hands.
You've built something in Experience Builder. Now let's get it out of the editor and into users' hands — correctly, the first time.
Here is the single most important concept in Experience Builder publishing: your app exists in two separate versions at all times. A draft version (what you see in the editor) and a published version (what users see). Changes you make in the editor are invisible to users until you explicitly click Publish.
Your EB app is like a restaurant menu. The draft is the version the chef is scribbling changes on in the kitchen. The published version is the laminated copy the customers see. Customers never see the chef's notes until someone prints a new menu and puts it on the tables.
What you see in the EB editor. Saved automatically or when you click Save. Only visible to you and org admins. Two config locations: the editor UI and Resources > config/config.json.
What end users see at the live URL. Only updates when you click Publish. Stored in the Data tab. This is the "real" app.
EB has two config files internally. The Data tab stores the published/live config. The Resources > config/config.json stores the draft/editor config. If you edit one through the AGOL Assistant API without updating the other, you will get desynced states — the editor shows empty fields, and saving from the editor wipes your changes. Always update draft first, then publish.
Let's walk through the actual publish process step by step. It takes about 10 seconds, but understanding what happens under the hood prevents a lot of confusion later.
After publishing, always test by opening the published URL in a different browser or an incognito window. The editor's "Live view" is NOT the same as the published app — it uses the draft config and your authenticated session. Testing in incognito catches permission issues that the editor hides.
Publish your app, then immediately open the published URL in an incognito/private browser window. Does the app load? Can you see the map data? If the map tiles load but data layers show "Unable to load" or are simply empty, you have a sharing problem — we'll cover that in Lesson 3.
Every Experience Builder app gets a URL when published. Understanding the URL structure helps with sharing, embedding, and troubleshooting.
| URL type | Format | When to use |
|---|---|---|
| Default published URL | experience.arcgis.com/experience/<appId> | Standard sharing for AGOL apps |
| Enterprise URL | <portal>/apps/experiencebuilder/experience/?id=<appId> | ArcGIS Enterprise deployments |
| Custom slug | experience.arcgis.com/experience/<custom-slug> | Cleaner URLs for public-facing apps |
| Org vanity URL | <org>.maps.arcgis.com/apps/experiencebuilder/experience/?id=<appId> | When your org has a custom domain configured |
The appId is a 32-character hexadecimal string — the AGOL item ID for your app. You can find it in the URL bar when editing, or on the item's details page.
Instead of a long hex ID, you can set a human-readable slug. Go to your app's item details page in AGOL, click Settings, and scroll to the Web Experience section. Enter a custom URL path like my-shelter-map. The URL becomes experience.arcgis.com/experience/my-shelter-map.
You can also pass URL parameters to control the app's initial state:
// Open to a specific page experience.arcgis.com/experience/abc123?page=Details // Open to a specific page and view (for multi-view pages) experience.arcgis.com/experience/abc123?page=Dashboard&views=Region-East // Pass data filters via URL (Message Action required) experience.arcgis.com/experience/abc123?page=Map&data_s=STATUS%3DOpen // Open with specific locale experience.arcgis.com/experience/abc123?locale=es
This is the lesson that will save you the most support tickets. 50% of "my app is broken" complaints are actually "I shared the app but not the data layers." Read this carefully.
You share your app with "Everyone" (public). You send the URL to stakeholders. They open it and see... an empty map. No features. No data. The basemap loads fine, but every operational layer is blank. Why? Because the app is shared publicly, but the feature layers, web maps, and hosted tables it references are still private. The app itself is just a shell — it pulls data from separate AGOL items, and each of those items has its own sharing level.
ArcGIS has three sharing levels, and they apply independently to every item:
| Level | Who can access | Common use |
|---|---|---|
| Private (Owner) | Only you and org admins | Work in progress, drafts |
| Organization | Anyone signed into your AGOL org | Internal staff tools |
| Everyone (Public) | Anyone with the URL, no login required | Public-facing apps, field deployments |
There is also Group sharing — you can share items with specific groups within your org. This is the best practice for most internal tools: create a group, add the right people, share the app AND all data items to that group.
Before sending a URL to anyone, verify that ALL of these are shared at the same level:
Intentionally share your app as public but leave one feature layer private. Open the published URL in incognito. Watch how the map loads the basemap perfectly, but the operational layer shows nothing. No error message — just silence. This is what your users experience when sharing is misconfigured. Now go fix it.
Sometimes you don't send users directly to the EB URL — instead, you embed the app inside another page. SharePoint, ArcGIS StoryMaps, internal portals, even plain HTML pages. The magic word is iframe.
<!-- Basic iframe embed --> <iframe src="https://experience.arcgis.com/experience/YOUR_APP_ID" width="100%" height="800" frameborder="0" allow="geolocation; fullscreen" style="border: none; border-radius: 8px;" ></iframe>
| Platform | How to embed | Notes |
|---|---|---|
| SharePoint Online | Add an "Embed" web part, paste the iframe code or EB URL | May require admin approval for external content. Modern pages support direct URL embed. |
| ArcGIS StoryMaps | Add an "Embed" block, paste the published EB URL | StoryMaps handles the iframe automatically. Works seamlessly. |
| ArcGIS Hub | Add an iframe card or embed widget with the EB URL | Hub respects AGOL sharing — if the EB app is public, Hub can show it. |
| Custom HTML | Paste the iframe code above | Full control over sizing, styling, and interaction. |
| Confluence / Wiki | Use the HTML macro or iframe macro | Corporate wikis often block iframes — check with IT first. |
<!-- Responsive embed — fills parent container --> <div style="position:relative; width:100%; height:0; padding-bottom:56.25%; overflow:hidden;"> <iframe src="https://experience.arcgis.com/experience/YOUR_APP_ID" style="position:absolute; top:0; left:0; width:100%; height:100%; border:none;" allow="geolocation; fullscreen" ></iframe> </div>
The URL you use for embedding is the same published URL. No special "embed mode" is needed. However, you can append URL parameters to customize the initial state:
?page=Dashboard — open to a specific page?locale=es — force a specific language?page=Map&locale=frIn field operations, you often need to get an app URL onto a phone fast. Nobody is going to type experience.arcgis.com/experience/8a2f3b... into a phone keyboard. QR codes and short links solve this.
Point phone camera, app opens. Perfect for printed materials, tent signs at shelters, or field briefing packets. Generate at qr-code-generator.com, goqr.me, or any free tool.
Use bit.ly, tinyurl.com, or your org's URL shortener to create memorable links like bit.ly/shelter-map-2026. Easy to say aloud in a briefing.
A QR code is just a barcode that encodes a URL. That's it. No magic, no special app needed — modern phone cameras decode them automatically. The short link is for humans who need to share the URL verbally: "Everyone go to bit.ly/shelter-map" is infinitely better than reading a 64-character URL over a radio.
More than half your users will access your app on a phone. If you haven't tested on mobile, you haven't tested. Here's what to check before you publish.
| Issue | Solution |
|---|---|
| Sidebar covers entire screen on mobile | Use the sidebar's "Auto close" option, or redesign as a separate page instead of a sidebar |
| Text too small to read | Use relative font sizes (rem, em) instead of small pixel values. Test at 320px viewport width. |
| Map controls overlap on narrow screens | Reduce the number of visible map tools. Use the map toolbar's compact mode. |
| Charts unreadable on phone | Simplify chart labels, reduce data series, or hide charts at small breakpoints and show a summary text widget instead. |
| Feature table doesn't scroll | Tables need horizontal scroll on mobile. Minimize columns or use a List widget instead. |
Open your published app on your phone. Try every workflow a user would perform: search, select features, open sidebars, view charts. Take notes on anything that feels awkward. If you can't comfortably use it one-handed on a 5-inch screen, your field workers can't either.
Your app is published and shared. Now let's make it professional — version control, security, performance, and discoverability.
Experience Builder does not have built-in version control like Git. There is no "undo" for a bad publish. Once you click Publish, the previous published version is overwritten permanently. This means you need your own version management strategy.
Here's the scenario: You're making changes to a live app that 200 people use daily. You accidentally delete a widget, reconfigure a data source, or break an Arcade expression. You don't notice. You publish. Now 200 users have a broken app, and you can't roll back because the previous version is gone. This happens more often than anyone admits.
Before making significant changes, clone the app from its AGOL item page. The clone is your backup. If the original breaks, re-clone from the backup.
Name clones with dates: "Shelter Map - Backup 2026-02-20". Keep the last 2-3 backups. Delete old ones to avoid clutter.
Maintain two copies: a "Dev" app for changes and a "Prod" app that's always stable. Only update Prod when Dev is fully tested. (See Lesson 13 for the full pattern.)
Remember: saving the draft does NOT affect the published version. You can safely experiment in the draft all day long. The published app remains stable. Only when you click Publish does the draft overwrite the live version. Use this to your advantage — make all changes in the draft, test thoroughly in Live View, and only publish when you're confident.
In Lesson 3 we covered the basics of sharing. Now let's go deeper. In a real deployment, permissions cascade through multiple layers, and understanding this chain is the difference between an app that "just works" and one that breaks mysteriously for certain users.
Each level in this chain has its own sharing settings. A user only sees data if they have permission at every level. If any link in the chain is restricted, the data disappears — usually silently, without an error message.
| Layer in the chain | What controls access | Where to configure |
|---|---|---|
| EB App item | Item sharing level (Private/Org/Public) | AGOL item details > Share |
| Web Map item | Item sharing level | AGOL item details > Share |
| Feature Layer item | Item sharing level | AGOL item details > Share |
| Feature Layer sublayers | Inherit from parent item | Can't independently share sublayers |
| Individual fields | View definition / field visibility in layer settings | Feature layer settings > Fields tab |
| Feature-level filtering | View definitions (SQL WHERE clause) | Web map layer properties or feature layer views |
Some feature layers require authentication even when the item is shared publicly. This happens with:
When a token is required, unauthenticated users see a login prompt or empty data. The solution is either: make the service fully public (if appropriate), use a proxy service, or accept that users must sign in.
What if you want some pages of your app to be public and other pages to require login? EB supports this through page visibility settings and the Login widget.
Anyone can view. No login required. Use for landing pages, public dashboards, and informational content. The app item must be shared publicly.
Only visible to authenticated users. Use for editing interfaces, admin panels, or pages that show sensitive data. Users must sign in to access.
Page visibility controls what pages appear in the app's navigation for different users. It does NOT prevent a determined user from accessing the underlying data. If someone knows the feature layer URL, they can query it directly (assuming it's shared). For true data security, configure permissions at the data layer level, not the page level. Page visibility is a UX feature, not a security boundary.
The default experience.arcgis.com/experience/abc123 URL is functional but not memorable. For professional deployments, you may want a custom domain or at least a cleaner URL.
| Option | Complexity | Result |
|---|---|---|
| Custom slug (Lesson 2) | Easy | experience.arcgis.com/experience/my-shelter-map |
| Org vanity URL | Medium | myorg.maps.arcgis.com/apps/experiencebuilder/... |
| ArcGIS Hub custom domain | Medium | gis.myorganization.org/pages/shelter-map |
| Reverse proxy / DNS redirect | Advanced | sheltermap.myorganization.org (redirects to EB URL) |
| Download & self-host (Developer Edition) | Advanced | Any URL you want — full control, but you manage hosting |
If your org uses ArcGIS Hub, you can embed EB apps within Hub pages and take advantage of Hub's custom domain feature. This gives you URLs like gis.redcross.org/pages/shelter-dashboard without any custom hosting. Hub handles the SSL certificate and domain routing. The EB app runs inside a Hub page layout, which also gives you headers, footers, and consistent branding across all your GIS apps.
A slow app is a broken app. Users on spotty cellular connections during field operations won't wait 15 seconds for your map to load. Optimize before you publish, not after you get complaints.
Compress all custom images. Use WebP format. Keep header/background images under 200KB. No uncompressed PNGs.
Minimize the number of features loaded. Use definition queries to filter data. Enable pagination on large layers.
Every widget is a network request. Consolidate where possible. One rich Text widget beats three simple ones.
| Optimization | Impact | How to do it |
|---|---|---|
| Enable feature layer caching | High | Feature layer settings > Cache Control. Set max age for relatively static data. |
| Use vector tile basemaps | High | Switch from raster to vector basemaps in your web map. Lighter, faster, and crisper on all screens. |
| Reduce initial visible layers | High | Set layers to not visible by default in the web map. Let users toggle them on. Fewer layers = faster initial load. |
| Compress custom images | Medium | Use tinypng.com or squoosh.app before uploading. Target <100KB per image. |
| Simplify geometry | Medium | For polygon layers, use generalized geometry. Detailed parcel boundaries aren't needed at state-level zoom. |
| Use Feature Layer Views | Medium | Create views that only include the fields and features you need. Smaller payloads, faster queries. |
| Minimize Arcade expressions | Low-Medium | Complex Arcade runs on every feature. Use server-side calculated fields instead of client-side Arcade for large datasets. |
| Lazy-load pages | Medium | Put heavy widgets on secondary pages. Only the initial page loads on startup. Users load other pages on demand. |
If your app takes more than 5 seconds to become usable on a 4G connection, you will lose users. Field workers will close the tab and call someone for the information instead. Use your browser's Developer Tools (F12 > Network tab) to measure actual load times. Sort by size — the largest files are your biggest opportunities for optimization.
Open Chrome DevTools (F12), go to the Network tab, check "Disable cache", and reload your published app. Note the total transfer size and load time. Now throttle the connection to "Slow 3G" in the Network panel dropdown and reload. This simulates what your field workers experience in rural areas. If it's painful to watch, it's painful to use.
If your app is public, you probably want people to find it. If it's internal, you want it to show up in your org's AGOL search. Either way, metadata matters.
For public-facing apps, search engines (Google) can index your EB app. The following affect how your app appears in search results:
| Element | Where it comes from | How to set it |
|---|---|---|
| Page title (browser tab) | EB app name (configured in EB editor > App Settings) | Keep it short, descriptive, keyword-rich |
| Meta description | AGOL item description (first 160 chars) | Write a compelling first sentence in your item description |
| Open Graph image | AGOL item thumbnail | Upload a 1200x630px image as your thumbnail for social media previews |
| URL slug | Custom slug (Lesson 2) | Use keyword-rich, hyphenated slugs |
When someone shares your app URL on Teams, Slack, Twitter, or LinkedIn, the platform shows a preview card. This card pulls from AGOL metadata. To make it look good:
Your AGOL item metadata is your app's resume. The title is your name, the description is your cover letter, the thumbnail is your headshot, and the tags are your skills. When someone searches AGOL or Google, these are all they see before deciding whether to click. Make the first impression count.
Multi-environment pipelines, analytics, disaster rapid-deployment, accessibility compliance, and the definitive pre-publish checklist.
For production apps used by hundreds or thousands of people, you need more than a single app with a "clone before editing" strategy. You need distinct environments: Dev, Staging, and Production.
Where you make and break things. Points to test data sources. Only accessible to the development team. Nobody cares if this breaks.
A near-exact replica of production. Points to production data (read-only) or a staging copy. Shared with testers and stakeholders for review before go-live.
The live app. Never edit directly in production. All changes flow through Dev and Staging first. This is the URL your users have bookmarked.
When cloning an app between environments, the data source IDs are embedded throughout the configuration. If DEV points to a test feature layer and PROD points to a production feature layer, you need to update every data source reference. In the EB editor, go to the Data panel and swap each source. Every widget connected to the old source will reconnect to the new one — but double-check. Widgets with Arcade expressions that reference data source IDs by their string ID will need manual updates.
Your app is live. How do you know if anyone is actually using it? And how do you find out when something breaks before your users tell you?
Built-in. No setup required. Shows views per day/week/month for any item. Go to the item details page > Usage tab. Limited but free.
Add a GA4 tracking ID to your EB app for detailed user behavior: page views, session duration, device types, geographic location, and custom events.
G-XXXXXXXXXX)If your app is used by disaster survivors, field workers dealing with PII, or vulnerable populations, think carefully about what analytics data you collect. GA4 collects IP-based location data by default. Disable "Google Signals" in GA4 settings if you don't need demographic data. Comply with your org's data governance policies. When in doubt, AGOL's built-in usage reports are safer because the data stays within Esri's platform.
When a disaster strikes, you don't have time to build an app from scratch. The first 24 hours are chaos. You need to go from zero to a live, shared, populated app in 30 minutes or less. This requires pre-built templates and a rehearsed deployment process.
A disaster app template is like a go-bag. You don't pack it during the earthquake — you pack it last Tuesday and grab it on the way out the door. Your EB templates should be ready to go, tested, and documented before the phone rings at 2 AM.
Sometimes the disaster evolves and you need to change data sources on an app that's already live and in use. Be careful:
If your app is used by the public or by government agencies, it likely needs to meet WCAG 2.1 AA and Section 508 accessibility standards. Even if it's not legally required, making your app accessible means more people can use it — including users with visual, motor, or cognitive disabilities. And during disasters, accessibility isn't optional: people with disabilities are disproportionately affected.
Experience Builder's built-in widgets have improved significantly, but they are not automatically WCAG compliant out of the box. Esri has made progress on keyboard navigation and ARIA labels, but custom themes, Arcade-generated HTML, and complex widget configurations can easily break accessibility. You are responsible for testing and fixing issues before publishing.
| WCAG Criterion | What it means for EB | How to check |
|---|---|---|
| 1.1.1 Non-text Content | All images need alt text. Map widgets need text alternatives for key information. | Check Image widgets for alt text. Verify map data is also available in a table or text summary. |
| 1.3.1 Info and Relationships | Headings must use proper heading hierarchy. Lists must be structured correctly. | Use a screen reader or browser accessibility inspector to check heading order (h1, h2, h3...). |
| 1.4.3 Contrast Minimum | Text must have at least 4.5:1 contrast ratio against its background. | Use Chrome DevTools color contrast checker or webaim.org/resources/contrastchecker. |
| 2.1.1 Keyboard Accessible | All functionality must be available via keyboard (Tab, Enter, Escape). | Put your mouse away. Navigate your entire app using only the keyboard. Every button, link, and interactive element must be reachable. |
| 2.4.3 Focus Order | Tab order must be logical — left to right, top to bottom, matching the visual layout. | Tab through the app and verify the focus indicator moves in a logical sequence. |
| 2.4.7 Focus Visible | The currently focused element must have a visible outline/indicator. | Tab through widgets — can you always see which element is focused? |
| 4.1.2 Name, Role, Value | All interactive widgets must have accessible names (ARIA labels). | Use axe DevTools browser extension to scan for ARIA issues. |
This is the checklist you run through before every publish. Print it. Bookmark it. Tape it to your monitor. It covers everything from previous lessons, condensed into a single actionable list. No excuses for missing something.
You now understand the full lifecycle of an Experience Builder app — from draft to published, from a single user to thousands, from a quick internal tool to a production-grade disaster operations platform. The lessons in this guide are cumulative: beginners can start sharing apps today, and advanced users can build deployment pipelines that scale. The pre-publish checklist above is your safety net. Use it every time.