SDK methods communicate with the native Grab SuperApp via JSBridge. They only work when your page is running inside the Grab SuperApp WebView. Calling a method outside that environment returns { status_code: 501 }.
Every SDK method returns a bridge response object with an HTTP-style status_code. SDK methods never throw — use type guards instead of try/catch.
import { ProfileModule, isSuccess, isError } from '@grabjs/superapp-sdk';
const profile = new ProfileModule();
const response = await profile.fetchEmail();
if (isSuccess(response)) {
console.log('Result:', response.result);
} else if (isError(response)) {
switch (response.status_code) {
case 403:
// Missing OAuth scope - call IdentityModule.authorize() then ScopeModule.reloadScopes()
break;
case 426:
// Grab app version too old - prompt user to update their app
break;
default:
console.error(`Error ${response.status_code}: ${response.error}`);
}
}
The SDK uses HTTP-style status codes for all responses:
| Code | Type | Description |
|---|---|---|
200 |
OK | Request successful, result contains response data |
204 |
No Content | Request successful, no data returned |
302 |
Redirect | Redirect in progress |
400 |
Bad Request | Invalid request parameters |
401 |
Unauthorized | Authentication required |
403 |
Forbidden | Insufficient permission (see @requiredOAuthScope tag) |
404 |
Not Found | Resource not found |
424 |
Failed Dependency | Underlying native request failed |
426 |
Upgrade Required | Grab app version too old (see @minimumGrabAppVersion tag) |
500 |
Internal Error | Unexpected SDK error |
501 |
Not Implemented | Outside Grab SuperApp environment |
Methods tagged with @requiredOAuthScope require specific permissions. If the user hasn't granted the required scope, the method returns 403. You must request authorization and reload scopes before retrying:
IdentityModule.authorize() to request the scope.ScopeModule.reloadScopes() to refresh the SDK's internal permission state.import {
LocationModule,
IdentityModule,
ScopeModule,
isSuccess,
isError,
} from '@grabjs/superapp-sdk';
const location = new LocationModule();
const identity = new IdentityModule();
const scope = new ScopeModule();
const response = await location.getCoordinate();
if (isError(response) && response.status_code === 403) {
// 1. Request authorization for the required scope
const auth = await identity.authorize({
clientId: 'your-client-id',
redirectUri: 'https://your-app.com/callback',
scope: 'mobile.geolocation', // The scope defined in @requiredOAuthScope
environment: 'production',
responseMode: 'in_place',
});
if (isSuccess(auth)) {
// 2. Reload scopes so the new permission is available
await scope.reloadScopes();
// 3. Retry the original call
const retry = await location.getCoordinate();
if (isSuccess(retry)) {
console.log('Result:', retry.result);
}
}
}
Type guards narrow the response type so TypeScript knows which fields are available:
| Guard | Matches |
|---|---|
isSuccess(r) |
200, 204 |
isOk(r) |
200 |
isNoContent(r) |
204 |
isRedirection(r) / isFound(r) |
302 |
isClientError(r) |
400, 401, 403, 404, 424, 426 |
isServerError(r) |
500, 501 |
isError(r) |
any 4xx or 5xx |
import { isSuccess, isOk, isNoContent, isError } from '@grabjs/superapp-sdk';
if (isSuccess(response)) {
// narrow further if needed
if (isOk(response)) console.log(response.result);
if (isNoContent(response)) console.log('done, no data');
}
if (isError(response)) {
// response.error: string is guaranteed here
console.error(response.error);
}
Some modules provide streaming methods for real-time data (location updates, media events). Subscribe to receive values over time:
import { LocationModule, isSuccess } from '@grabjs/superapp-sdk';
const location = new LocationModule();
const subscription = location.observeLocationChange().subscribe({
next: (response) => {
if (isSuccess(response)) console.log(response.result);
},
complete: () => console.log('Stream ended'),
});
// Always unsubscribe when done to conserve battery and resources
subscription.unsubscribe();
You can also await a stream method directly to get its first value.