or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

advertising-monetization.mdapplication-lifecycle.mdauthentication.mdcore-bridge.mddevice-features.mdgeolocation.mdindex.mdlaunch-parameters.mdmiddleware.mdpayments-commerce.mdqr-barcode-scanning.mdsocial-features.mdstorage-data.mdui-display.mduser-data.md

geolocation.mddocs/

0

# Geolocation Services

1

2

Access device location data and geographic information with privacy controls and accuracy options for location-based features.

3

4

## Capabilities

5

6

### Location Data Access

7

8

Get current device location with coordinates and accuracy information.

9

10

```typescript { .api }

11

/**

12

* Get device geolocation data

13

* @returns Current location coordinates and accuracy

14

*/

15

function send(method: 'VKWebAppGetGeodata'): Promise<{

16

lat: number;

17

long: number;

18

accuracy?: number;

19

}>;

20

21

/**

22

* Set location for the application context

23

* @param props.location - Location string or coordinates

24

*/

25

function send(method: 'VKWebAppSetLocation', props: {

26

location: string;

27

}): Promise<{ result: true }>;

28

```

29

30

**Usage Examples:**

31

32

```typescript

33

// Get current location

34

try {

35

const location = await bridge.send('VKWebAppGetGeodata');

36

console.log('Latitude:', location.lat);

37

console.log('Longitude:', location.long);

38

console.log('Accuracy:', location.accuracy, 'meters');

39

40

// Use location data

41

displayUserLocation(location.lat, location.long);

42

findNearbyPlaces(location.lat, location.long);

43

} catch (error) {

44

console.error('Location access failed:', error);

45

handleLocationError(error);

46

}

47

48

// Set application location context

49

try {

50

await bridge.send('VKWebAppSetLocation', {

51

location: 'Moscow, Russia'

52

});

53

console.log('App location context set');

54

} catch (error) {

55

console.error('Failed to set location:', error);

56

}

57

58

// Check location availability before use

59

const canGetLocation = await bridge.supportsAsync('VKWebAppGetGeodata');

60

if (canGetLocation) {

61

const geoData = await bridge.send('VKWebAppGetGeodata');

62

processLocationData(geoData);

63

} else {

64

// Fallback: IP-based location or manual input

65

useAlternativeLocationMethod();

66

}

67

```

68

69

### Location-Based Features

70

71

Implement common location-based functionality patterns.

72

73

```typescript

74

// Distance calculation

75

function calculateDistance(

76

lat1: number, lon1: number,

77

lat2: number, lon2: number

78

): number {

79

const R = 6371; // Radius of Earth in kilometers

80

const dLat = (lat2 - lat1) * Math.PI / 180;

81

const dLon = (lon2 - lon1) * Math.PI / 180;

82

const a =

83

Math.sin(dLat/2) * Math.sin(dLat/2) +

84

Math.cos(lat1 * Math.PI / 180) * Math.cos(lat2 * Math.PI / 180) *

85

Math.sin(dLon/2) * Math.sin(dLon/2);

86

const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));

87

return R * c; // Distance in kilometers

88

}

89

90

// Nearby places finder

91

async function findNearbyPlaces(userLat: number, userLon: number) {

92

const places = [

93

{ name: 'Coffee Shop', lat: 55.7558, lon: 37.6176 },

94

{ name: 'Restaurant', lat: 55.7539, lon: 37.6208 },

95

{ name: 'Park', lat: 55.7527, lon: 37.6156 }

96

];

97

98

const nearbyPlaces = places

99

.map(place => ({

100

...place,

101

distance: calculateDistance(userLat, userLon, place.lat, place.lon)

102

}))

103

.filter(place => place.distance <= 5) // Within 5km

104

.sort((a, b) => a.distance - b.distance);

105

106

console.log('Nearby places:', nearbyPlaces);

107

return nearbyPlaces;

108

}

109

110

// Location-based content filtering

111

async function getLocationBasedContent() {

112

try {

113

const location = await bridge.send('VKWebAppGetGeodata');

114

115

// Determine region/country from coordinates

116

const region = await getRegionFromCoordinates(location.lat, location.long);

117

118

// Filter content based on location

119

const localizedContent = await fetchContentForRegion(region);

120

121

return {

122

location,

123

region,

124

content: localizedContent

125

};

126

} catch (error) {

127

// Fallback to default content

128

return {

129

location: null,

130

region: 'default',

131

content: await fetchDefaultContent()

132

};

133

}

134

}

135

136

// Reverse geocoding helper

137

async function getRegionFromCoordinates(lat: number, lon: number): Promise<string> {

138

// Simple region detection based on coordinates

139

if (lat >= 55 && lat <= 56 && lon >= 37 && lon <= 38) {

140

return 'moscow';

141

} else if (lat >= 59 && lat <= 60 && lon >= 30 && lon <= 31) {

142

return 'saint-petersburg';

143

} else if (lat >= 40 && lat <= 85 && lon >= 19 && lon <= 170) {

144

return 'russia';

145

} else {

146

return 'international';

147

}

148

}

149

```

150

151

### Location Permission Management

152

153

Handle location permissions and user privacy controls.

154

155

```typescript

156

// Location permission checker

157

class LocationManager {

158

private hasLocationPermission = false;

159

160

async checkLocationPermission(): Promise<boolean> {

161

try {

162

// Check if geolocation is supported

163

const isSupported = await bridge.supportsAsync('VKWebAppGetGeodata');

164

if (!isSupported) {

165

return false;

166

}

167

168

// Check granted permissions

169

const permissions = await bridge.send('VKWebAppGetGrantedPermissions');

170

this.hasLocationPermission = permissions.permissions.includes('location');

171

172

return this.hasLocationPermission;

173

} catch (error) {

174

console.error('Permission check failed:', error);

175

return false;

176

}

177

}

178

179

async requestLocation(): Promise<{ lat: number; long: number } | null> {

180

try {

181

// Check permission first

182

if (!await this.checkLocationPermission()) {

183

console.log('Location permission not granted');

184

return null;

185

}

186

187

// Get location

188

const location = await bridge.send('VKWebAppGetGeodata');

189

return location;

190

} catch (error) {

191

this.handleLocationError(error);

192

return null;

193

}

194

}

195

196

private handleLocationError(error: any) {

197

switch (error.error_data?.error_code) {

198

case 6: // Permission denied

199

console.error('Location permission denied by user');

200

this.showPermissionDialog();

201

break;

202

case 10: // Location not available

203

console.error('Location services not available');

204

this.showLocationUnavailableMessage();

205

break;

206

case 7: // Timeout

207

console.error('Location request timed out');

208

this.showTimeoutMessage();

209

break;

210

default:

211

console.error('Location error:', error);

212

this.showGenericErrorMessage();

213

}

214

}

215

216

private showPermissionDialog() {

217

// Show UI explaining why location is needed

218

console.log('Please enable location permissions in VK app settings');

219

}

220

221

private showLocationUnavailableMessage() {

222

// Show message about location services

223

console.log('Location services are not available on this device');

224

}

225

226

private showTimeoutMessage() {

227

// Show timeout message with retry option

228

console.log('Location request timed out. Please try again.');

229

}

230

231

private showGenericErrorMessage() {

232

// Show generic error message

233

console.log('Unable to get location. Please try again later.');

234

}

235

}

236

```

237

238

### Location Caching and Optimization

239

240

Optimize location requests with caching and accuracy controls.

241

242

```typescript

243

// Location cache manager

244

class LocationCache {

245

private cache: {

246

location: { lat: number; long: number; accuracy?: number };

247

timestamp: number;

248

maxAge: number;

249

} | null = null;

250

251

async getLocation(maxAge: number = 300000): Promise<{ lat: number; long: number } | null> {

252

// Check cache first

253

if (this.cache &&

254

Date.now() - this.cache.timestamp < maxAge &&

255

(this.cache.location.accuracy || 100) <= 100) {

256

console.log('Using cached location');

257

return this.cache.location;

258

}

259

260

try {

261

// Get fresh location

262

const location = await bridge.send('VKWebAppGetGeodata');

263

264

// Update cache

265

this.cache = {

266

location,

267

timestamp: Date.now(),

268

maxAge

269

};

270

271

console.log('Got fresh location');

272

return location;

273

} catch (error) {

274

// Return cached location if fresh request fails

275

if (this.cache) {

276

console.log('Using stale cached location due to error');

277

return this.cache.location;

278

}

279

throw error;

280

}

281

}

282

283

clearCache() {

284

this.cache = null;

285

}

286

287

getCacheAge(): number {

288

return this.cache ? Date.now() - this.cache.timestamp : -1;

289

}

290

}

291

292

// Usage example

293

const locationCache = new LocationCache();

294

295

async function getCurrentLocation() {

296

try {

297

// Get location with 5-minute cache

298

const location = await locationCache.getLocation(300000);

299

return location;

300

} catch (error) {

301

console.error('Failed to get location:', error);

302

return null;

303

}

304

}

305

```

306

307

## Platform Availability

308

309

Geolocation services are available on the following platforms:

310

311

- **iOS WebView**: Full GPS access with VKWebAppGetGeodata

312

- **Android WebView**: Full GPS access with VKWebAppGetGeodata

313

- **Web/Desktop**: Limited availability (may not work in all contexts)

314

315

Always check method support and handle permissions appropriately:

316

317

```typescript

318

async function initializeLocation() {

319

const canGetLocation = await bridge.supportsAsync('VKWebAppGetGeodata');

320

321

if (canGetLocation) {

322

const locationManager = new LocationManager();

323

const hasPermission = await locationManager.checkLocationPermission();

324

325

if (hasPermission) {

326

const location = await locationManager.requestLocation();

327

if (location) {

328

console.log('Location initialized:', location);

329

return location;

330

}

331

} else {

332

console.log('Location permission required');

333

}

334

} else {

335

console.log('Geolocation not supported on this platform');

336

}

337

338

return null;

339

}

340

```

341

342

## Privacy and Best Practices

343

344

1. **Request location only when needed** - Don't request location access immediately on app start

345

2. **Explain why location is needed** - Show clear UI explaining the benefit to users

346

3. **Handle permission denial gracefully** - Provide alternative functionality when location is denied

347

4. **Cache location data** - Avoid frequent location requests to preserve battery

348

5. **Respect accuracy** - Use appropriate accuracy thresholds for your use case

349

6. **Provide manual alternatives** - Allow users to manually enter location when automatic detection fails

350

351

```typescript

352

// Privacy-conscious location request

353

async function requestLocationWithExplanation(reason: string) {

354

// Show explanation first

355

const userConsent = confirm(`This app needs your location to ${reason}. Allow location access?`);

356

357

if (!userConsent) {

358

console.log('User declined location access');

359

return null;

360

}

361

362

try {

363

const location = await bridge.send('VKWebAppGetGeodata');

364

console.log('Location granted:', location);

365

return location;

366

} catch (error) {

367

console.error('Location request failed:', error);

368

return null;

369

}

370

}

371

```