The Open Geospatial Consortium (OGC) KML 2.2 Standard [OGC 07-147r2] has a few areas that are not fully defined.
There exist a few inconsistencies between the Google KML Reference, the Google Earth™ implementation, and
the OGC KML Standard. There are also subtle differences between versions of Google Earth in its interpretation of KML.
The official OGC KML 2.2 Standard (07-147r2) supersedes both Google KML 2.2 Reference and a related
KML 2.2 Reference - An OGC Best Practice (07-113r1) document so if any conflict exists, the official
KML standard is assumed correct.
OGC KML 2.3 Standard (12-007r2) was recently published and cleans up many of the areas that were not clearly defined
in the KML 2.2 specification. Google Earth does not yet support the new KML 2.3 features.
This page documents some of these issues to promote discussions on issues related to interoperability
and fill in gaps in the KML standard.
There are also some undocumented elements and limitations in Google Earth that are listed here.
Table of contents:
If there are any errors in this document or something missing please feel free to contact me
and share your suggestion.
- BalloonStyle Entity Replacement
- Strict validation of KML
- Encoding Special Characters in KML
- Representing time in KML
- Snippet vs snippet
- LatLonAltBox discrepency
- LatLonBox assertion
- Limitations of Google Earth with respect to KML
Special thanks to Barry Hunter for some additions to the limitations of Google Earth list.
entity replacement is clearly defined in the Google KML Reference, but only mentioned in the OGC KML 2.2 Specification [section 6.5]
as an example that includes $[name] and $[description] and the full list is not defined. Likewise,
it is still only mentioned in an example in the OGC KML 2.3 Specification.
The following entities are defined in KML as implemented in Google Earth:
||To include property address in the balloon
||To include property description in the balloon
To include To here - From here driving directions in the balloon
||To include property id in the balloon
||To include property name in the balloon
||To include property address in the balloon
||To include property snippet in the balloon
||To include property Snippet in the balloon
- $[phoneNumber] and $[snippet] are undocumented BalloonStyle entities implemented in Google Earth.
- Entity names are case-sensitive so $[Snippet] cannot be interchangeable with $[snippet].
For consistency Snippet and snippet entities should be interchangeable (but currently they are not)
and refer to the Snippet or snippet element
(which are mutually exclusive) in the respective feature, whichever is defined.
Google Earth literally bends over backwards to parse loosely defined KML files that have elements out of order,
wrong XML encoding, KML files labeled as KMZ files, and so forth. Of special note is badly formatted and
ambiguous coordinates which prior to Google Earth 6.0 were allowed.
For example, below is a coordinate string for a LineString that innocently enough looks fine, but it breaks
two rules in the KML spec. Click here for the KML example.
The KML 2.2 Specification and Google KML Reference documentation are both clear on the rules of coordinates:
- Insert whitespace between tuples
- Do *not* include whitespace within a tuple
The author of this KML should have instead correctly formatted the coordinate
as following KML snippet, which conforms to the standard:
But strangely enough Google Earth versions 4.x and 5.x ignored whitespace within tuples and discarded the extra coma after the first
tuple showing the line where the author had intended.
The problem is that to a machine the coordinate is ambiguous and could be interpreted in multiple ways and a straight-forward
parser tokenizing on whitespace fails to parse this correctly. Google Earth just so happened to interpret it such a way that it worked.
Another problem is that the KML XML Schema validates coordinate strings as a kml:coordinatesType with this simple definition:
Nowhere does the KML XML Schema restrict tuples of longitude and latitude as decimal degrees in the range -180,+180 and -90,+90 respectively.
So a value such as "a,b,c d,e,f"
would validate correctly using only XML Schema-based validation.
This, however, changed as of Google Earth 6.0, which now interprets the coordinates element
accordingly to the strict rules mentioned above so this badly formed coordinate gets normalized
and rewritten as the following:
When opened in Google Earth these two tuples now get converted into six tuples.
- Each whitespace in the coordinates value marks the start of a new tuple and each value in our example
becomes the longitude with a latitude and altitude set at zero.
- Notice the sixth tuple with 567.8 as the longitude clearly not in the valid +/- 180 range.
Google Earth version 6.1 and higher gives no error or warning, but it does show a portion of the line segment in a different hemisphere.
If the line's altitudeMode
value is changed to clampToGround
then you will see the line wrap around most of the globe
- clearly not what the original KML author had in mind. Click here
for the full example KML.
This should be a good argument for the need of stronger validation. Additional validation best practices can be found
The KML 2.2 Specification
Google KML Reference
state you must use XML entity/character references or the CDATA element to escape angle brackets,
apostrophes, and other special characters.
Here is an example:
This is an image
If you prefer not to use the CDATA element, you can use entity references to replace the special characters:
This is an image
What is not defined is how to encode angle brackets, apostrophes, and special characters to appear as-is
in the HTML display. Suppose you want to show some raw KML or XML tags to display in the description rather
than be used to markup the text. The entity references (e.g., <) within the CDATA block does not work for this.
To show raw markup in the description you must use character entities with the ASCII or hex code for the special
characters. To display a less than sign (<) you must use: <
To display "<href> foo.kml </href>" as a literal string you would write the following using
either ASCII codes or hex codes to represent the special characters:
1. Character entity encoding using ASCII code for special characters:
<href> foo.kml </href>
2. Character entity encoding using hex code for special characters:
<href> foo.kml </href>
KML can represent dates and time in its features. The time can be a TimeStamp
using the kml:dateTimeType
structure allowing for an absolute time using the ISO-8601
dateTime format or several date variations as defined in following table:
However, what is not documented is that the representations other than dateTime
have implicit meaning for the fields that are not specified such that just specifying only
the year using the gYear type (e.g. 1997 is equivalent to 1997-01-01 T 00:00:00Z).
Any date or time represents the exact instant for that time even if the full month, day
of month or time is not specified. And likewise the date (YYYY-MM-DD) type implies
the time at 00:00:00Z.
Note this contradicts the W3C XML Schema definitions for which the KML types are derived from.
For example, gYear is defined “specifically, it is a set of one-year long, non-periodic
instances; e.g. lexical 1999 to represent the whole year 1999” and likewise gYearMonth spans the
The first TimeSpan (example 1) in KML fragment above begins at 1999 and ends at 2000
does not represent the whole year for 2000, but for the instant the calendar becomes
2000 on January 1st and is equivalent to the second TimeSpan (example 2). The XML Schema
definition would instead represent the first time period (1999-2000) as 1999-01-01 to 2000-12-31
not 1999-01-01 to 2000-01-01 as implemented in Google Earth so this is a discrepancy.
Try out the provided example to see for yourself.
The target "A" placemark has a start and end time as 1999 and 2000 respectively as
in example 1 above. The "1" placemark has the start and end time with absolute time
as in example 2. Click on the marker "B" placemark to change the time window
from 2000-12-01 to 2000-12-31, which will in turn hide the "A" and "1" placemarks
showing that they are equivalent.
See also time inheritance discussed in the next topic.
Time is defined on Features in the Google KML Reference, but time on nested features is not clearly
defined there. If a placemark is a child element of a Document or Folder that has a Timespan or
Timestamp when does it become visible? Does it make a difference if the placemark itself
has a Timespan or Timestamp? It wasn't clear how these cases are interpreted from the KML unless
you refer to section 9.6.2 of the OGC KML 2.2 standard which describes the AbstractContainerGroup
and the correct behavior of inherited time.
“... the value of the following Feature elements shall be inherited by all Feature
members of a hierarchy unless overruled by the presence of such elements locally
[list includes TimePrimitive]. Inheritance of these elements continues to any depth
of nesting, but if overruled by a local declaration, then the new value is inherited
by all its children in turn.”
While this was not implemented correctly in Google Earth 5.0.x, it was, however, fixed
in 5.1.3509.4636 (beta). It is no longer a Google Earth defect, but the Google's KML Reference
should reflect this paragraph from the OGC document so misinterpretations can be avoided.
KMZ is briefly defined in the OGC KML 2.2 Specification as a ZIP-compressed KML file in the introduction.
The specification and KML Reference do not specify that it should use ZIP 2.0
or "legacy" compatible compression only (i.e. stored or deflate method), otherwise the .kmz file might not uncompress
in all geobrowsers (including Google Earth). Using the more advanced compression methods (e.g., bzip2, LZMA, etc.)
will not be compatible. These are undocumented implementation details.
As of April 2013, a Google Maps help center article was updated to reflect this information.
KMZ has been included in Annex C of the OGC KML 2.3 with this information as of August 2015. The author of this errata worked
with OGC technical working group to incorporate a description of KMZ into the specification.
Having whitespace and special characters in paths or filenames of entries inside a KMZ file should be avoided
to ensure it's interoperable across all platforms and all KML viewers. Google Earth, for example, requires a strict exact match between NetworkLink target href URLs and the corresponding KMZ zip entry.
Other KML/Earth Viewers may handle whitespace and URL encoding differently.
Following table shows examples that match (meaning the target NetworkLink opens in Google Earth)
and those that do not.
||NetworkLink Link href
||KMZ zip entry
The value of the "NetworkLink Link href" column is exactly as the entry would
appear in the Link href tag, so example 1 would appear in root KML file as this:
Whitespace is disallowed within the URI syntax (see section 2.4.3 in http://www.ietf.org/rfc/rfc2396.txt)
Technically the URI "test 1.kml" in example 1 is not valid, but this works as you would expect in Google Earth
and the link loaded correctly.
The URI in example 2 "test%202.kml" is properly URL encoded with whitespace encoded as %20 string, but notice
to match the zip entry, it must match exactly and the zip entry is identical to the URL-encoded form.
The URI in example 3 "test%203.kml" is encoded in same fashion in example 2, but it doesn't match the target zip
entry which is "test 3.kml".
This means the relative URIs for corresponding entries in KMZ files are matched as-is
and no URL decoding is applied.
URI in example 4 "test 4.kml" does not exactly match the KMZ entry "test%204.kml" so the Link fails to load.
Recommendation: Keep it simple and avoid using whitespace and special characters in paths or filenames
for entries within KMZ files.
The KML specification and associated XML Schema
clearly show the element "Snippet" form deprecated and "snippet" as the approved form to use:
<complexType name="AbstractFeatureType" abstract="true">
<documentation>Snippet deprecated in 2.2</documentation>
<element ref="kml:Snippet" minOccurs="0"/>
<element ref="kml:snippet" minOccurs="0"/>
<element name="snippet" type="string"/>
<element name="Snippet" type="kml:SnippetType"/>
<complexType final="#all" name="SnippetType">
<attribute default="2" name="maxLines" type="int" use="optional"/>
However, the Google Earth documentation only shows the deprecated "Snippet" form of kml:SnippetType:
The examples in the Google KML Reference documentation and related samples also show the element Snippet
Google Earth, fortunately, supports both forms of snippet and Snippet. However, note that if you use the $[Snippet]
substitution entity in a BalloonStyle
text then it must exactly match the capitalization of Snippet or snippet as used the KML placemark. So if you use Snippet
in your KML then must use $[Snippet] to reference it in the BalloonStyle. The substitution entities in the BalloonStyle text
are case-sensitive so $[Snippet] and $[snippet] cannot be used interchangeably. This behavior is undocumented.
This issue has been reported to Google in July 2010
and likewise to the OGC as feedback to the KML 2.2 specification. Note that Galdos Systems,
who is the organization that runs the KML validator web site and chaired the KML 2.2 working group, documents
in their KML validation suite as ATC 76
where Snippet is deprecated and warns at the informational level if found in KML files.
In cases of contradition, the official OGC KML 2.2 Standard supersedes the Google KML Reference so
kml:snippet is the recommended form.
See also the Snippet limitations in Google Earth.
The OGC KML 2.2 specification and associated XML Schema defines latitude, and the north/south components of a kml:LatLonAltBox
used in Regions and kml:LatLonBox
used in GroundOverlay as the following:
<element name="latitude" type="kml:angle90Type" default="0.0"/>
<element name="north" type="kml:angle180Type" default="180.0"/>
<element name="south" type="kml:angle180Type" default="-180.0"/>
Simply put, north and south fields are optional in the Region/LatLonAtBox and GroundOverlay/LatLonBox elements and north and south types are of the
"kml:angle180Type" type whose default values are +180, -180 respectively, but the spec states that north and south valid values (which should represent
the Latitude min/max bounds) are in the range 0 to ±90 not ±180 so the default values are out of the valid range.
The corrected changes to the schema should be the following:
<element name="north" type="kml:angle90Type" default="90.0"/>
<element name="south" type="kml:angle90Type" default="-90.0"/>
The relevant sections in the OGC KML spec (OGC 07-147r2) can be found in 9.14.3 where the description
is correct with a valid range from -90 to 90 but then lists the type as angle180Type.
Fortunately, this is not an issue with Google Earth since it requires north and south child elements
on a LatLonAltBox and LatLonBox otherwise the Region is not active or the GroundOverlay is not drawn.
What is affected is that XML Schema-based validation will not flag KML files with out-of-range
north and south values (greater than 90 and less than -90) and KML libraries using the Schema-driven
defaults may use the out of range defaults for these values if the elements are missing.
The KML 2.2 - Abstract Test Suite: OGC document: # 07-134r2 defines following test assertion:
ATC 11: LatLonBox states following constraints:
* kml:north > kml:south
* kml:east > kml:west
Pass if the assertion is satisfied; fail otherwise. The default envelope for a kml:GroundOverlay is the entire surface of the WGS 84 ellipsoid.
By testing north > south and east > west, we are testing for a non-zero area.
Reference: OGC-07-147r2: cl. 11.3.2
However, the kml:east > kml:west constraint doesn't hold if GroundOverlay LatLonBox bounds cross anti-meridian (i.e., west >= 0 AND east < 0)
in which case this rule needs clarification.
For example, let west = [Korea] +125 lon, east = [California,US] -115 lon
east > west constraint is valid only if bounds don't cross anti-meridian (i.e., west < 0 OR east >= 0)
The east > west assertion in ATC 11 is invalid if bounds GroundOverlay LatLonBox bounds cross anti-meridian as in above example
and must add the condition (west < 0 OR east >= 0) to be correct.
OGC KML Test Suite document should be changed in ATC 11 assertion to:
kml:east > kml:west *only if* kml:west < 0 OR kml:east >= 0
Google Earth supports the full KML 2.2 specification with which it can parse and render.
However, the Google Earth client user interface (including Google Earth Pro) has some restrictions with a few KML tags
that the user cannot create and/or edit.
The following lists some of these restrictions where the end-user must edit the raw KML
to use some elements of the KML specification. Most of these limitations are for the lesser used
or "advanced" KML features. KML developers should be aware of what Google Earth can and cannot do
as a KML authoring tool and create their KML accordingly.
- The address represents an unstructured address written as a standard street, city, state address,
and/or as a postal code.
The address is usually added automatically in search results when you perform a search and it is displayed
in the Placemark's description balloon. However, you cannot change the address or add it to a placemark
if it doesn't already exist unless you edit raw KML.
- The xal:AddressDetails element is a structured address formatted in the eXtensible Address Language (xAL).
Currently, Google Earth does not use the AddressDetails element. It uses <address> instead.
With the exception of Google Earth Pro that populates both the AddressDetails and address elements as result
of a search, you still must edit the raw KML to add/edit this element.
- The atom:author element is data about the author of the KML file.
This information is displayed in geo search results in Google Earth, but to add/edit this field you must edit the raw KML.
- The atom:link specifies the URL of the website containing this KML or KMZ file.
This information is displayed in geo search results in Google Earth, but to add/edit this field you must edit the raw KML.
- The BalloonStyle specifies how the description balloon for placemarks is drawn.
The BalloonStyle is handled as expected by Google Earth but the client does not expose the BalloonStyle. End-users
cannot edit the BalloonStyle or add it without editing the raw KML.
- <drawOrder> and <gx:drawOrder>
- The drawOrder and gx:drawOrder specify the stacking order for drawing overlapping ground overlays and lines or polygons,
respectively. See <drawOrder> and
The drawOrder option only appears in the edit placemark dialog under altitude tab
if the geometry is a Polygon or GroundOverlay. However, the
drawOrder option does not appear if the geometry is a LineString or MultiGeometry
for placemarks or for a ScreenOverlay. In case of a LineString, MultiGeometry or
ScreenOverlay, the end-user must edit the raw KML to insert/edit the drawOrder values.
Note that drawOrder in Google KML Reference documentation
only mentions overlays and lines (polygons are not even mentioned). Further, handling of drawOrder on polygons is separate
from that of lines and a polygon with higher drawOrder is not drawn on top of a line
with a lower drawOrder value. Lines are always drawn on top of polygons.
- The ExtendedData element offers techniques for adding custom data to a KML Feature.
- Having either untyped data/values or typed fields using the <Schema> element can appear in the description balloon,
but the user cannot edit nor add ExtendedData to a new KML Feature. These can only be edited or added to the raw KML. Note: Google Earth Pro
creates Schema/ExtendedData elements when it imports CSV files, but the ExendedData elements cannot be edited directly in the client.
On a related note, if the KML Feature has ExtendedData but no description then the description popup shows the fields in an formatted
HTML table form. If user tries to edit the description property then the description field is shown as empty, which can be confusing
to a user unaware of the KML Feature using ExtendedData.
- ExtendedData also allows arbitrary XML Data (explicit non-KML namespace) to associate with a Feature.
See Adding Arbitrary XML Data to a Feature.
Google Earth preserves this data, but does not process it nor does it allow the user to view/edit the contents via the Google Earth client.
The data exists as metadata possibly showing the association of the feature to its source or provider. Such data could be utilized
by custom applications that can parse the KML and use it accordingly. This powerful capability is not used very often and considered to be
used by advanced KML developers so Google Earth client does not expose this to the end user.
- GroundOverlay element draws an image overlay draped onto the terrain. See <GroundOverlay>.
Some "advanced" elements of the GroundOverlay are hidden from the user in the Google Earth client. See Link
element for details.
- The hotspot tag specifies the position within the Icon that is "anchored" to the <Point> specified in the Placemark.
The hotspot offsets for standard Google Icons is automatically calculated so the icons appear in the correct orientation with respect to the location
on the map. The user must specify this only if custom icons are used in which case the KML author is expected to produce the raw KML since hotspot
tags cannot be added or edited using the Google Earth client for custom icons.
- IconStyle specifies how icons for point Placemarks are drawn. See <IconStyle>.
With the exception of hotspot discussed above, the only other property of the IconStyle not editable in Google Earth is
the heading element.
Adding or editing the heading requires editing the raw KML.
This is one of those lesser used elements of KML, which can be very useful to show aircraft or ship heading with just the icon.
- The Link specifies the location of Model, NetworkLink and Overlay resources.
The httpQuery and
elements, which are part of the <Link>
element, cannot be added or edited without changing the raw KML.
The details of a Link (e.g. as used in NetworkLink) is typically part of a KML feed so this is often created by a KML developer
making a KML feed available.
- Model specify 3D objects described in a COLLADA file. See <Model>.
Some "advanced" elements of the Model are hidden from the user in the Google Earth client. See Link
element for details.
- NetworkLink references a KML file or KMZ archive on a local or remote network.
Some "advanced" elements of the NetworkLink are hidden from the user in the Google Earth client. See Link
element for details.
- Controls the behavior of files fetched by a <NetworkLink>.
These elements are handled as expected by Google Earth but the client does not expose the NetworkLinkControl element. End-users
cannot edit the NetworkLinkControl or add it without editing the raw KML. NetworkLinkControl (like regions) in particular are
"advanced" and error-prone so hiding this from the typical user of Google Earth is not unreasonable.
- A Polygon is defined by an outer boundary and 0 or more inner boundaries.
You can create the outer boundary of Polygons in Google Earth, but you cannot directly create or edit the inner boundaries
of a polygon without editing the raw KML.
For example, here is a KML
polygon with inner boundaries.
- A region contains a bounding box that describes an area of interest defined by geographic coordinates and altitudes.
Regions are handled as expected by Google Earth but the client does not expose the Region element. End-users
cannot edit the Region or add it without editing the raw KML.
Regions (and NetworkLinkControl) in particular are advanced and easily misused
so hiding this from the typical user of Google Earth is not unreasonable but a "region" tab in Google Earth
would be very helpful for advanced KML authors. The ability to show an outline of the region on the map in
"edit" mode would be a time saver. Maybe this could be a feature of Google Earth Pro.
- Schema specifies a custom KML schema that is used to add custom data to KML Features.
The Schema in conjunction with ExtendedData element are rendered in Google Earth but end-user cannot directly edit the Schema without
editing the raw KML. Google Earth Pro will automatically produce Schema and ExtendedData elements for some data when
imported (e.g. ESRI shape files) in the KML that is generated.
- ScreenOverlay draws an image overlay fixed to the screen. See <ScreenOverlay>.
The ScreenOverlay element is rendered in Google Earth but end-user cannot create a ScreenOverlay and the x/y position
cannot be edited.
- The Snippet overrides the description which is displayed in the Places pane (in the Sidebar) under the name of the feature.
The Snippet is essential if the description is too large or rather has multimedia content which isn't appropriate to show in the
Places pane. The Snippet if provided will be displayed in Places pane instead of the description but user cannot add or edit the
Snippet contents. This can be confusing to a user editing a placemark in Google Earth who tries to edit the description and the
Places pane doesn't reflect the change. Only looking at the raw KML would show the Snippet being used.
Only the description can be changed, which is displayed as usual in the description popup.
Also entity names in BalloonStyles are case-sensitive so $[Snippet] is not interchangeable with $[snippet].
See Snippet vs snippet discussion for more details.
- StyleMap element is used to provide separate normal and highlighted styles for a placemark. See <StyeMap>.
StyleMaps are created behind the scenes when applying a style to a feature, but users cannot
edit the separate styles independently without changing the raw KML.
- tessellate specifies whether to allow the lines or polygons to follow the terrain. See <tessellate>.
The tessellate element is added to new paths or polygons that are created by default but user cannot edit tessellate
element without editing the raw KML.
- TimeSpan represents an extent in time bounded by begin and end dateTimes. See <TimeSpan>.
The TimeSpan element triggers the time slider in Google Earth but user
cannot edit or add the time to a Feature without editing the raw KML.
- TimeStamp represents a single moment in time. See <TimeStamp>.
The TimeStamp element as with TimeSpan triggers the time slider
in Google Earth but user cannot edit or add the time to a Feature without editing the raw KML.
- visibility specifies whether a feature is drawn when it is initially loaded. See <visibility>.
The handling of visibility in how it cascades to children via inheritance is probably the only one or a few
details in the Google Earth implementation that contradicts the OGC KML specification. In related discussions
for this it was reported that what got in the OGC KML spec was wrong but in either case there is a
The OGC KML 2.2 Standard (OGC 07-147r2 126.96.36.199.1) states "in order for a Feature to be visible, the kml:visibility tag
of all its ancestors shall also be set to 1 or true." 
So the following
example would imply that the Placemark named "A" would not be visible when it is loaded in Google Earth
since its ancestor's visibility is not set to 1 or "true".
However, the reverse is true and this placemark is visible in Google Earth.
Google Earth implements visibility such that visibility on a child element overrides visbility
even if the visibility is not explicitly defined and this violates the standard as stated above.
By default the visibility value is 1 or true so to hide all children in a Folder or Document, all of the children
must explicitly have visibility 0 rather than just setting it once at the Folder/Document level.
This was reported as a bug
in 2009 and Google responded “Visibility has always been overridden on the child element
level, and changing this would break existing code.
Likewise there are restrictions to KML Elements Supported in Google Maps.
- OGC KML Standard (Specification and related documents)
- KML Best Practice (Validation, tools, metadata, and more)
- Google KML Reference
- KML Validator service
Google Earth (TM) and Google Maps (TM) are registered trademarks of Google Inc. KML4Earth is not affiliated with Google.
KML4Earth is not an official source of information on Google or Google Earth. But, we try to get reliable information whenever we can.
Created and maintained by jasonm1