[{"data":1,"prerenderedAt":495},["ShallowReactive",2],{"docs-\u002Fdocs\u002Fconcepts\u002Fencoded-polylines":3,"_apollo:default":494,"_apollo:stationEditor":494,"_apollo:feedManagement":494,"_apollo:transferAnalyst":494},{"id":4,"title":5,"body":6,"description":485,"extension":486,"meta":487,"navigation":333,"path":489,"seo":490,"stem":491,"__hash__":492,"lastUpdated":493},"content\u002Fdocs\u002Fconcepts\u002Fencoded-polylines.md","Encoded polylines",{"type":7,"value":8,"toc":476},"minimark",[9,25,28,50,55,180,190,225,229,232,235,261,264,267,271,274,277,285,289,299,403,411,451,454,464,472],[10,11,12,13,18,19,24],"p",{},"An encoded polyline is a string of printable ASCII characters that encodes a list of integers. Transitland and ",[14,15,17],"a",{"href":16},"\u002Fdocumentation\u002Frouting-platform","Interline Routing Platform"," APIs use encoded polylines to reduce the size of responses sent to browsers and other clients. The format is the ",[14,20,23],{"href":21,"target":22},"https:\u002F\u002Fdevelopers.google.com\u002Fmaps\u002Fdocumentation\u002Futilities\u002Fpolylinealgorithm","_blank","encoded polyline algorithm"," from Google Maps. The algorithm was designed for map geometries and applies to any list of integers.",[10,26,27],{},"The APIs use encoded polylines for two kinds of data:",[29,30,31,39],"ul",{},[32,33,34,38],"li",{},[35,36,37],"strong",{},"Geographic data",": lists of coordinates, such as a journey geometry from a routing engine or the shape of a trip.",[32,40,41,44,45,49],{},[35,42,43],{},"Tabular data",": rows of a grid, such as the timetable grids of the ",[14,46,48],{"href":47},"\u002Fdocumentation\u002Frest-api\u002Fpatterns","route patterns endpoint",", in which some cells are null.",[51,52,54],"h2",{"id":53},"where-the-apis-use-encoded-polylines","Where the APIs use encoded polylines",[56,57,58,77],"table",{},[59,60,61],"thead",{},[62,63,64,68,71,74],"tr",{},[65,66,67],"th",{},"API",[65,69,70],{},"Field",[65,72,73],{},"Data",[65,75,76],{},"Precision",[78,79,80,116,136,163],"tbody",{},[62,81,82,95,106,109],{},[83,84,85,89,90,94],"td",{},[14,86,88],{"href":87},"\u002Fdocumentation\u002Frouting-platform\u002Froute","Street routing",", ",[14,91,93],{"href":92},"\u002Fdocumentation\u002Frouting-platform\u002Fmap-matching","map matching",", and other Valhalla endpoints",[83,96,97,101,102,105],{},[98,99,100],"code",{},"shape"," in responses, and ",[98,103,104],{},"encoded_polyline"," in trace requests",[83,107,108],{},"Geographic",[83,110,111,112,115],{},"6 in the default ",[98,113,114],{},"json"," format",[62,117,118,125,131,133],{},[83,119,120,124],{},[14,121,123],{"href":122},"\u002Fdocumentation\u002Frouting-platform\u002Ftransit-otp","Transit routing",", from the Transitland Routing API",[83,126,127,128],{},"Each leg's ",[98,129,130],{},"legGeometry.points",[83,132,108],{},[83,134,135],{},"5",[62,137,138,143,153,155],{},[83,139,140],{},[14,141,142],{"href":47},"REST route patterns",[83,144,145,146,149,150],{},"Each shape's ",[98,147,148],{},"polyline"," or ",[98,151,152],{},"polyline6",[83,154,108],{},[83,156,157,158,160,161],{},"5 for ",[98,159,148],{},", 6 for ",[98,162,152],{},[62,164,165,169,174,177],{},[83,166,167],{},[14,168,142],{"href":47},[83,170,171,172],{},"Each timetable grid's ",[98,173,148],{},[83,175,176],{},"Tabular",[83,178,179],{},"Not scaled",[10,181,182,183,186,187,189],{},"Valhalla's ",[98,184,185],{},"shape_format"," parameter does not change shapes in the default ",[98,188,114],{}," response format. It applies in two cases:",[29,191,192,214],{},[32,193,194,195,198,199,201,202,205,206,209,210,213],{},"With ",[98,196,197],{},"format: osrm",", it selects ",[98,200,152],{}," (the default), ",[98,203,204],{},"polyline5",", or ",[98,207,208],{},"geojson"," for each route's ",[98,211,212],{},"geometry",".",[32,215,216,217,221,222,224],{},"The ",[14,218,220],{"href":219},"\u002Fdocumentation\u002Frouting-platform\u002Fmatrix","matrix"," endpoint returns a shape for each pair only when the request sets ",[98,223,185],{},", in the format it names.",[51,226,228],{"id":227},"how-the-algorithm-works","How the algorithm works",[10,230,231],{},"The algorithm encodes each integer in a list as its difference from the previous integer. The first integer is encoded as its difference from 0. Small differences encode to fewer characters, so lists of gradually changing values, such as consecutive points on a line or consecutive times in a timetable row, encode compactly.",[10,233,234],{},"Each difference is encoded as follows:",[236,237,238,241,244,251],"ol",{},[32,239,240],{},"Shift the value left by one bit. If the value is negative, invert all bits, so that the lowest bit records the sign.",[32,242,243],{},"Split the result into 5-bit chunks, starting with the lowest bits.",[32,245,246,247,250],{},"Set the ",[98,248,249],{},"0x20"," bit on every chunk except the last, to indicate that another chunk follows.",[32,252,253,254,257,258,213],{},"Add 63 to each chunk, to produce a printable character from ",[98,255,256],{},"?"," to ",[98,259,260],{},"~",[51,262,37],{"id":263},"geographic-data",[10,265,266],{},"A line is encoded as each point's latitude and longitude, in that order. Each latitude is encoded as its difference from the previous point's latitude, and each longitude as its difference from the previous point's longitude. The order of latitude and longitude is the reverse of GeoJSON, which puts longitude first.",[268,269,76],"h3",{"id":270},"precision",[10,272,273],{},"Before encoding, each coordinate is multiplied by 10 to the power of the precision and rounded to an integer. Five digits of precision, also called polyline5, is 1.1 meters of latitude. Six digits, also called polyline6, is 11 centimeters of latitude.",[10,275,276],{},"The string does not record its precision, so the decoder must be given the precision. Decoding at the wrong precision does not return an error. It returns incorrect coordinates:",[29,278,279,282],{},[32,280,281],{},"A polyline6 string decoded at five digits returns coordinates 10 times too large. A point in San Francisco is returned as 377.95, -1223.94.",[32,283,284],{},"A polyline5 string decoded at six digits returns coordinates one tenth of their correct values. The same point is returned as 3.78, -12.24.",[268,286,288],{"id":287},"decoding","Decoding",[10,290,291,292,298],{},"Most languages have a polyline library that takes the precision as an argument. In JavaScript, ",[14,293,295],{"href":294,"target":22},"https:\u002F\u002Fwww.npmjs.com\u002Fpackage\u002F@mapbox\u002Fpolyline",[98,296,297],{},"@mapbox\u002Fpolyline",":",[300,301,306],"pre",{"className":302,"code":303,"language":304,"meta":305,"style":305},"language-js shiki shiki-themes github-light github-dark","import polyline from '@mapbox\u002Fpolyline'\n\n\u002F\u002F A Valhalla shape, at six digits: [[lat, lon], ...]\nconst points = polyline.decode(shape, 6)\n\n\u002F\u002F The same shape as a GeoJSON LineString, in [lon, lat] order\nconst line = polyline.toGeoJSON(shape, 6)\n","js","",[98,307,308,328,335,342,371,376,382],{"__ignoreMap":305},[309,310,313,317,321,324],"span",{"class":311,"line":312},"line",1,[309,314,316],{"class":315},"szBVR","import",[309,318,320],{"class":319},"sVt8B"," polyline ",[309,322,323],{"class":315},"from",[309,325,327],{"class":326},"sZZnC"," '@mapbox\u002Fpolyline'\n",[309,329,331],{"class":311,"line":330},2,[309,332,334],{"emptyLinePlaceholder":333},true,"\n",[309,336,338],{"class":311,"line":337},3,[309,339,341],{"class":340},"sJ8bj","\u002F\u002F A Valhalla shape, at six digits: [[lat, lon], ...]\n",[309,343,345,348,352,355,358,362,365,368],{"class":311,"line":344},4,[309,346,347],{"class":315},"const",[309,349,351],{"class":350},"sj4cs"," points",[309,353,354],{"class":315}," =",[309,356,357],{"class":319}," polyline.",[309,359,361],{"class":360},"sScJk","decode",[309,363,364],{"class":319},"(shape, ",[309,366,367],{"class":350},"6",[309,369,370],{"class":319},")\n",[309,372,374],{"class":311,"line":373},5,[309,375,334],{"emptyLinePlaceholder":333},[309,377,379],{"class":311,"line":378},6,[309,380,381],{"class":340},"\u002F\u002F The same shape as a GeoJSON LineString, in [lon, lat] order\n",[309,383,385,387,390,392,394,397,399,401],{"class":311,"line":384},7,[309,386,347],{"class":315},[309,388,389],{"class":350}," line",[309,391,354],{"class":315},[309,393,357],{"class":319},[309,395,396],{"class":360},"toGeoJSON",[309,398,364],{"class":319},[309,400,367],{"class":350},[309,402,370],{"class":319},[10,404,405,406,298],{},"In Python, ",[14,407,409],{"href":408,"target":22},"https:\u002F\u002Fpypi.org\u002Fproject\u002Fpolyline\u002F",[98,410,148],{},[300,412,416],{"className":413,"code":414,"language":415,"meta":305,"style":305},"language-python shiki shiki-themes github-light github-dark","import polyline\n\n# A Valhalla shape, at six digits: [(lat, lon), ...]\npoints = polyline.decode(shape, 6)\n\n# In GeoJSON (lon, lat) order\ncoordinates = polyline.decode(shape, 6, geojson=True)\n","python",[98,417,418,423,427,432,437,441,446],{"__ignoreMap":305},[309,419,420],{"class":311,"line":312},[309,421,422],{},"import polyline\n",[309,424,425],{"class":311,"line":330},[309,426,334],{"emptyLinePlaceholder":333},[309,428,429],{"class":311,"line":337},[309,430,431],{},"# A Valhalla shape, at six digits: [(lat, lon), ...]\n",[309,433,434],{"class":311,"line":344},[309,435,436],{},"points = polyline.decode(shape, 6)\n",[309,438,439],{"class":311,"line":373},[309,440,334],{"emptyLinePlaceholder":333},[309,442,443],{"class":311,"line":378},[309,444,445],{},"# In GeoJSON (lon, lat) order\n",[309,447,448],{"class":311,"line":384},[309,449,450],{},"coordinates = polyline.decode(shape, 6, geojson=True)\n",[51,452,43],{"id":453},"tabular-data",[10,455,456,457,460,461,463],{},"Route patterns timetables are grids, with a row for each stop and a column for each trip. Some cells are null, such as the shape distances of a trip without a shape. With ",[98,458,459],{},"encoding=polyline",", each row is a single string that encodes one integer per cell. The integers are not scaled, and a ",[98,462,213],{}," marks a null cell.",[10,465,466,467,471],{},"Polyline libraries decode coordinate pairs and cannot decode these rows. The ",[14,468,470],{"href":469},"\u002Fdocumentation\u002Frest-api\u002Fpatterns#encoded-responses","route patterns page"," describes the grid format and includes a worked example and a decoder.",[473,474,475],"style",{},"html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":305,"searchDepth":330,"depth":330,"links":477},[478,479,480,484],{"id":53,"depth":330,"text":54},{"id":227,"depth":330,"text":228},{"id":263,"depth":330,"text":37,"children":481},[482,483],{"id":270,"depth":337,"text":76},{"id":287,"depth":337,"text":288},{"id":453,"depth":330,"text":43},"How Transitland and Interline Routing Platform APIs use encoded polylines to compress geographic and tabular data, the difference between five and six digits of precision, and how to decode them.","md",{"layout":488},"documentation","\u002Fdocs\u002Fconcepts\u002Fencoded-polylines",{"title":5,"description":485},"docs\u002Fconcepts\u002Fencoded-polylines","1InA4aoyuuxkjyukcxZBbCRHeA6k0ZWuISHpmPfYhoE","2026-11-02T16:09:19-08:00","{}",1793664647719]