Turn your Earth Engine scripts into shareable web applications. This module walks you through the complete process from code to published app that anyone can access.
Learning objectives
- Convert a script into an app-ready format.
- Create a full-screen app layout.
- Publish and manage Earth Engine apps.
- Share apps with specific users or the public.
- Understand app limitations and best practices.
Why it matters
Apps democratize your analysis. A published app lets stakeholders, policymakers, or the var map = ui.Map(); map.setCenter(-82.3, 29.6, 10); // Add a simple layer var image = ee.Image('LANDSAT/LC08/C02/T1_L2/LC08_044034_20210623') .multiply(0.0000275).add(-0.2); var ndvi = image.normalizedDifference(['SR_B5', 'SR_B4']); map.addLayer(ndvi, {min: 0, max: 0.8, palette: ['brown', 'yellow', 'green']}, 'NDVI'); // Create a simple panel var panel = ui.Panel({ widgets: [ ui.Label('NDVI Explorer', {fontWeight: 'bold', fontSize: '20px'}), ui.Label('This app displays NDVI for a Landsat 8 scene.') ], style: {width: '300px', padding: '20px'} }); // Build the app layout var splitPanel = ui.SplitPanel({ firstPanel: panel, secondPanel: map, orientation: 'horizontal', wipe: false }); ui.root.add(splitPanel);
What you should see
A full-screen app with a sidebar panel on the left and an interactive map on the right. This is the foundation for more complex apps.
Step-by-step: Publishing an app
Step 1: Prepare your script
- Remove all
print()statements (they clutter the console). - Use
ui.root.clear()to remove default Code Editor elements. - Create your own map with
ui.Map(). - Test thoroughly before publishing.
Step 2: Open the publish dialog
- In the Code Editor, click the Apps button (top-right).
- Click New App.
- Fill in the app details:
- Name: Choose a descriptive name (appears in URL)
- App URL: Will be
username.users.earthengine.app/view/appname
Step 3: Configure access
| Access Level | Who Can View | Use Case |
|---|---|---|
| Private | Only you | Testing before release |
| Anyone with link | People you share the URL with | Sharing with collaborators |
| Public | Anyone on the internet | Open access for stakeholders |
Step 4: Publish and share
- Click Publish.
- Copy the generated URL.
- Share the link via email, social media, or embed in a website.
Complete app example: Interactive layer selector
This app lets users choose which layer to display:
ui.root.clear();
// Create map
var map = ui.Map();
map.setCenter(-82.3, 29.6, 10);
// Load image
var image = ee.Image('LANDSAT/LC08/C02/T1_L2/LC08_044034_20210623')
.multiply(0.0000275).add(-0.2);
// Calculate indices
var ndvi = image.normalizedDifference(['SR_B5', 'SR_B4']).rename('NDVI');
var ndwi = image.normalizedDifference(['SR_B3', 'SR_B5']).rename('NDWI');
// Visualization parameters
var layers = {
'True Color': {
image: image.select(['SR_B4', 'SR_B3', 'SR_B2']),
vis: {min: 0, max: 0.3}
},
'False Color': {
image: image.select(['SR_B5', 'SR_B4', 'SR_B3']),
vis: {min: 0, max: 0.4}
},
'NDVI': {
image: ndvi,
vis: {min: 0, max: 0.8, palette: ['brown', 'yellow', 'green']}
},
'NDWI': {
image: ndwi,
vis: {min: -0.5, max: 0.5, palette: ['brown', 'white', 'blue']}
}
};
// Create dropdown
var select = ui.Select({
items: Object.keys(layers),
value: 'True Color',
onChange: function(key) {
map.layers().reset();
var layer = layers[key];
map.addLayer(layer.image, layer.vis, key);
}
});
// Initialize with first layer
select.setValue('True Color', true);
// Create panel
var panel = ui.Panel({
widgets: [
ui.Label('Landsat 8 Viewer', {fontWeight: 'bold', fontSize: '24px'}),
ui.Label('Select a layer to display:'),
select,
ui.Label(''),
ui.Label('Data: Landsat 8 Collection 2', {fontSize: '12px', color: 'gray'})
],
style: {width: '250px', padding: '20px'}
});
// Layout
ui.root.add(ui.SplitPanel(panel, map));
App layout patterns
Sidebar layout (most common)
ui.root.add(ui.SplitPanel({
firstPanel: sidebarPanel, // Controls
secondPanel: map, // Map
orientation: 'horizontal'
}));
Top bar layout
ui.root.add(ui.SplitPanel({
firstPanel: headerPanel, // Title and controls
secondPanel: map, // Map
orientation: 'vertical'
}));
Split map comparison
var leftMap = ui.Map();
var rightMap = ui.Map();
var linker = ui.Map.Linker([leftMap, rightMap]);
ui.root.add(ui.SplitPanel({
firstPanel: leftMap,
secondPanel: rightMap,
wipe: true // Enable swipe comparison
}));
Pro tips
- Add a loading message: Use
ui.Label('Loading...')that you remove when data loads. - Include attribution: Add data source and your name/institution.
- Test on mobile: Many users will access via phone.
- Version your apps: Create
myapp-v1,myapp-v2to preserve old versions. - Add help text: Users won't know what controls do without labels.
Managing published apps
- Update: Edit your script and click "Publish" again to update the app.
- Delete: Apps button → select app → Delete.
- View analytics: Currently limited, but you can track via your own URL shortener.
- Embed: Use an iframe:
<iframe src="app-url" width="100%" height="600"></iframe>
Common mistakes
- Leaving
print()statements that clutter the console. - Forgetting
ui.root.clear()(shows Code Editor elements). - Using the default
Mapinstead ofui.Map(). - Publishing without thorough testing.
- Not adding instructions for users.
- Overloading with too many features at once.
App limitations
- Computation limits: Same as Code Editor (may time out on complex analyses).
- No file upload: Users can't upload their own data.
- No download: Users can't directly download results (use Export workarounds).
- URL length: Very long URLs can break some sharing platforms.
Quick self-check
- Why do you need
ui.root.clear()in an app? - What's the difference between
Mapandui.Map()? - How do you update a published app?
- What layout widget creates a sidebar + map view?
Next steps
- UI Widgets - more interactive controls
- Public Engagement Overview
- Lab 20: Deploying GEE Apps