Arcade is Esri's expression language. It runs inside ArcGIS Online — in popup templates, label expressions, dynamic styles, field calculations, and a handful of other contexts. It looks like JavaScript. It isn't JavaScript. That gap is where most GIS developers lose an hour they didn't plan to lose.
Before AI, fluency in Arcade was a specialist skill. You either knew which functions existed in which context, or you found out the hard way when your expression returned null and nothing told you why. Now you can describe what you want in plain English, give Claude the right context, and get working Arcade back in thirty seconds.
But "the right context" is doing a lot of work in that sentence. This article is about what that means.
Arcade Is Not JavaScript
If you know JavaScript, Arcade will feel familiar enough to be dangerous. The variable syntax is similar. The logic constructs are the same. The functions are not.
JavaScript: str.length — Arcade: no .length property. Use Count(str) instead.
JavaScript: str.match(/pattern/) — Arcade: Match() exists in some contexts. Not all.
JavaScript: arr.indexOf(val) — Arcade: IndexOf(arr, val).
JavaScript: Math.round(n) — Arcade: Round(n).
None of this is unreasonable. It's just different, and the differences aren't always documented in a way that's easy to find when you're in the middle of building something.
The deeper issue: Arcade's function library is smaller than JavaScript's. Things you'd reach for instinctively don't exist. You end up writing what feels like a workaround for something that should be a one-liner.
// Parse the last 4 characters of a field value
// JavaScript: fieldVal.slice(-4)
// Arcade — no negative slice, so:
Mid($feature.FIELD_NAME, Count($feature.FIELD_NAME) - 4, 4)
That's not wrong. It's just longer than it looks like it should be. AI writes it correctly on the first try, every time, because it knows the function library. You describe the intent; it handles the syntax.
Context Is Everything
The same Arcade expression can fail in three different places for three different reasons — not because the logic is wrong, but because the context changes what's available.
Esri calls these profiles. Each profile is a different execution environment with a different set of functions, a different set of available variables, and a different expected return type.
Popup profile — runs when a feature is clicked. Returns a dictionary (for Arcade popups) or a string (for text elements). Has access to $feature. Does not have access to $map.
Dynamic Style / Visualization profile — runs per feature to drive renderer logic. Returns a value used to classify or symbolize the feature. Has access to $feature and feature statistics. More functions available than popup.
Label profile — runs to generate label text. Returns a string. Has access to $feature. No access to feature set functions like FeatureSetByPortalItem() without additional configuration.
Field calculation profile — runs in a field calculator. Returns a value written to the field. Different again.
The practical consequence: an Arcade expression that works perfectly in the Dynamic Style panel will fail silently in a popup. The function that was available there isn't available here. The return type that made sense there — a number, a color string — isn't what's expected here.
This is the part that trips up experienced developers. You test in one place, move to another, and it breaks. The error message, if there is one, rarely tells you why.
The Gotcha Catalog
These are the specific things that catch people, by context:
In popup Arcade (text expression profile):
- Return type must be a string. If you return a number, it renders as nothing.
Match()is listed in the documentation but unavailable in the popup text profile in AGOL. Wrap withIIf()or useWhen()instead.FeatureSetByPortalItem()requires the user to be signed in and the layer to be accessible. Fails silently for public users if the layer is private.- Long text with
\nnewlines doesn't render as line breaks in all widget contexts. UseTextFormatting.NewLineinstead.
In Dynamic Style (visualization profile):
- You can return a color directly as a hex string or an array — but the renderer type determines which format is accepted.
- Normalize expressions run separately from color expressions. Confusing them produces renderers that look right but calculate wrong.
In label expressions:
- Concatenation with
+works. Template literals don't. Round()works.Ceil()andFloor()are not available in all versions.
Across all contexts:
Len()is not a function.Count()is the equivalent for strings.- Field names are case-sensitive in some contexts and not in others. When in doubt, match the exact case from the layer definition.
- Null values need explicit handling.
IsEmpty($feature.FIELD)before you operate on it, or you'll get unexpected results on features with null values.
What to Give AI
AI handles all of this well — if you give it the right prompt. The failure mode is asking for "Arcade to do X" without specifying the context. The expression you get back may use functions that don't exist in your profile, or return the wrong type, or reference variables that aren't available.
A prompt that works:
"Write an Arcade expression for an ArcGIS Online popup text element. The expression should display the field GIFT_DATE formatted as Month DD, YYYY. The field is stored as a Unix timestamp in milliseconds. Return a string. Avoid Match() — it's unavailable in this context."
What that prompt includes:
- The profile (popup text element)
- The specific field and its format
- The expected return type
- A known gotcha to avoid
A prompt that doesn't work:
"Write Arcade to format a date field."
The second prompt will get you an expression. It may or may not run in your context. You'll find out when you paste it in and it returns null.
AI as a Compiler for Intent
The best mental model: think of AI as a compiler that translates your intent — described in plain English, in terms of what you want to accomplish — into Arcade that accounts for the quirks of the specific profile you're targeting.
You don't need to memorize that Mid() is how Arcade slices strings, or that Count() is what Len() should have been called, or that TextFormatting.NewLine is the line break constant for popup expressions. You need to know what you want the expression to do, which profile it runs in, and what type it should return. Give AI those three things and you get working code.
The skill that used to take months of painful discovery — learning which functions work where, which gotchas to watch for, how to structure expressions for each profile — compresses to the skill of writing a clear prompt. Clear prompts require knowing the vocabulary: profile names, return types, the names of the gotchas even if not the solutions.
That vocabulary is learnable in an afternoon. The old skill took much longer.
Arcade is worth learning. It runs everywhere in AGOL, it's the only way to drive dynamic symbology and popup logic without SDK code, and the expressions that are possible with it — especially in popup templates — are more powerful than most GIS developers realize. The barrier was always the quirky function library and the context-specific rules. That barrier is lower now.
Know the profiles. Know what to tell AI. Get working Arcade.