MCPcopy Index your code
hub / github.com/Shopify/mobile-buy-sdk-android

github.com/Shopify/mobile-buy-sdk-android @2026.4.0

Chat with this repo
repository ↗ · DeepWiki ↗ · release 2026.4.0 ↗ · + Follow
450 symbols 1,091 edges 39 files 49 documented · 11%
What it actually does AI analysis from the code graph — generated when you open this
loading…
README

Mobile Buy SDK

Tests GitHub license GitHub release

Mobile Buy SDK

The Mobile Buy SDK makes it easy to create custom storefronts in your mobile app. The SDK connects to the Shopify platform using GraphQL, and supports a wide range of native storefront experiences.

Installation

Mobile Buy SDK for Android is represented by a runtime module that provides support to build and execute GraphQL queries.

Versioning

As of the 2025.1.0 release, the Mobile Buy SDK now uses a modified CalVer versioning scheme. This was done to align with the quarterly Storefront GraphQL API releases and bring clarity to what version a library release corresponds to.

The format is yyyy.mm.patch, where the first two components match the API version, and the last component corresponds to non-breaking bug fixes within an API version cycle. In practice, this means that unlike SemVer, there may be breaking GraphQL schema changes between "minor" versions. Learn more about API release schedules at Shopify.

Repositories

As of the 2025.1.0 release, the library is published both to Maven Central as well as GitHub Packages.

Gradle:

implementation("com.shopify.mobilebuysdk:buy3:2026.4.0")

Maven:

<dependency>
  <groupId>com.shopify.mobilebuysdk</groupId>
  <artifactId>buy3</artifactId>
  <version>2026.4.0</version>
</dependency>

Getting started

The Buy SDK is built on GraphQL. The SDK handles all the query generation and response parsing, exposing only typed models and compile-time checked query structures. It doesn't require you to write stringed queries, or parse JSON responses.

You don't need to be an expert in GraphQL to start using it with the Buy SDK (but it helps if you've used it before). The sections below provide a brief introduction to this system, and some examples of how you can use it to build secure custom storefronts.

Code Generation

The Buy SDK is built on a hierarchy of generated classes that construct and parse GraphQL queries and response. These classes are generated manually by running a custom Ruby script. Most of the generation functionality and supporting classes live inside the library. It works by downloading the GraphQL schema, generating Java class hierarchy, and saving the generated files to the specified folder path. In addition, it provides overrides for custom GraphQL scalar types like Date.

Request Models

All generated request models are represented by interfaces with one method define that takes single argument, generated query builder. Every query starts with generated Storefront.QueryRootQueryDefinition interface that defines the root of your query.

Let's take a look at an example query for a shop's name:

QueryRootQuery query = Storefront.query(new Storefront.QueryRootQueryDefinition() {
    @Override public void define(final Storefront.QueryRootQuery rootQueryBuilder) {
      rootQueryBuilder.shop(new Storefront.ShopQueryDefinition() {
        @Override public void define(final Storefront.ShopQuery shopQueryBuilder) {
          shopQueryBuilder.name();
        }
      });
    }
})

In this example:

  • Storefront.query is the entry point for building GraphQL queries.
  • Storefront.QueryRootQueryDefinition represents the root of the query where we ask for the shop's rootQueryBuilder.shop.
  • Storefront.ShopQueryDefinition represents the subquery definition for shop field, where we request the shop's shopQueryBuilder.name.

Request models are generated in such way where lambda expressions can come in handy. We can use lambda expressions to make the initial query more concise:

QueryRootQuery query = Storefront.query(rootQueryBuilder ->
  rootQueryBuilder
    .shop(shopQueryBuilder ->
      shopQueryBuilder
        .name()
    )
)

The code example above produces the following GraphQL query (you can call query.toString() to see a built GraphQL query):

query {
  shop {
    name
  }
}

Response models

All generated response models are derived from the AbstractResponse type. This abstract class provides a similar key-value type interface to a Map for accessing field values in GraphQL responses. You should never use these accessors directly, and instead rely on typed, derived properties in generated subclasses.

Let's continue the example of accessing the result of a shop name query:

// The right way

Storefront.QueryRoot response = ...;

String name = response.getShop().getName();

Never use the abstract class directly:

// The wrong way (never do this)

AbstractResponse response = ...;

AbstractResponse shop = (AbstractResponse) response.get("shop");
String name = (String) shop.get("name");

Again, both of the approaches produce the same result, but the former case is safe and requires no casting since it already knows about the expected type.

The Node protocol

GraphQL schema defines a Node interface that declares an id field on any conforming type. This makes it convenient to query for any object in the schema given only its id. The concept is carried across to the Buy SDK as well, but requires a cast to the correct type. You need to make sure that the Node type is of the correct type, otherwise casting to an incorrect type will return a runtime exception.

Given this query:

ID id = new ID("NkZmFzZGZhc");
Storefront.query(rootQueryBuilder ->
  rootQueryBuilder
    .node(id, nodeQuery ->
      nodeQuery
        .onProduct(productQuery ->
          productQuery
            .title()
            ...
        )
    )
);

The Storefront.Order requires a cast:

Storefront.QueryRoot response = ...;

String title = ((Storefront.Product)response.getNode()).getTitle();

Aliases

Aliases are useful when a single query requests multiple fields with the same names at the same nesting level, since GraphQL allows only unique field names. Multiple nodes can be queried by using a unique alias for each one:

Storefront.query(rootQueryBuilder ->
  rootQueryBuilder
    .node(new ID("NkZmFzZGZhc"), nodeQuery ->
      nodeQuery
      .onCollection(collectionQuery ->
        collectionQuery
          .withAlias("collection")
          .title()
          .description()
          ...
      )
    )
    .node(new ID("GZhc2Rm"), nodeQuery ->
      nodeQuery
        .onProduct(productQuery ->
          productQuery
            .withAlias("product")
            .title()
            .description()
            ...
        )
    )
);

Accessing the aliased nodes is similar to a plain node:

Storefront.QueryRoot response = ...;

Storefront.Collection collection = (Storefront.Collection) response.withAlias("collection").getNode();
Storefront.Product product = (Storefront.Product) response.withAlias("product").getNode();

Learn more about GraphQL aliases.

GraphClient

The GraphClient is a network layer built on top of Square's OkHttp client that prepares GraphCall to execute query and mutation requests. It also simplifies polling and retrying requests. To get started with GraphClient, you need the following:

  • Your shop's .myshopify.com domain
  • Your API key, which you can find in your shop's admin
  • OkHttpClient (optional), if you want to customize the configuration used for network requests or share your existing OkHttpClient with the GraphClient
GraphClient.builder(this)
  .shopDomain(BuildConfig.SHOP_DOMAIN)
  .accessToken(BuildConfig.API_KEY)
  .httpClient(httpClient) // optional
  .build()

GraphQL specifies two types of operations: queries and mutations. The GraphClient exposes these as two type-safe operations, while also offering some conveniences for retrying and polling in each.

Queries

Semantically, a GraphQL query operation is equivalent to a GET RESTful call. It guarantees that no resources will be mutated on the server. With GraphClient, you can perform a query operation using:

GraphClient graphClient = ...;
Storefront.QueryRootQuery query = ...;

QueryGraphCall call = graphClient.queryGraph(query);

For example, let's take a look at how we can query for a shop's name:

GraphClient graphClient = ...;

Storefront.QueryRootQuery query = Storefront.query(rootQuery ->
  rootQuery
    .shop(shopQuery ->
      shopQuery
        .name()
    )
);

QueryGraphCall call = graphClient.queryGraph(query);

call.enqueue(new GraphCall.Callback<Storefront.QueryRoot>() {

  @Override public void onResponse(@NonNull GraphResponse<Storefront.QueryRoot> response) {
    String name = response.data().getShop().getName();
  }

  @Override public void onFailure(@NonNull GraphError error) {
    Log.e(TAG, "Failed to execute query", error);
  }
});

Learn more about GraphQL queries.

Mutations

Semantically a GraphQL mutation operation is equivalent to a PUT, POST or DELETE RESTful call. A mutation is almost always accompanied by an input that represents values to be updated and a query to fetch fields of the updated resource. You can think of a mutation as a two-step operation where the resource is first modified, and then queried using the provided query. The second half of the operation is identical to a regular query request.

With GraphClient, you can perform a mutation operation using:

GraphClient graphClient = ...;
Storefront.MutationQuery query = ...;

MutationGraphCall call = graphClient.mutateGraph(query);

For example, let's take a look at how we can reset a customer's password using a recovery token:

GraphClient graphClient = ...;

Storefront.CustomerResetInput input = new Storefront.CustomerResetInput("c29tZSB0b2tlbiB2YWx1ZQ", "abc123");

Storefront.MutationQuery query = Storefront.mutation(rootQuery ->
  rootQuery
    .customerReset(new ID("YSBjdXN0b21lciBpZA"), input, payloadQuery ->
      payloadQuery
        .customer(customerQuery ->
          customerQuery
            .firstName()
            .lastName()
        )
        .userErrors(userErrorQuery ->
          userErrorQuery
            .field()
            .message()
        )
    )
);

MutationGraphCall call = graphClient.mutateGraph(query);

call.enqueue(new GraphCall.Callback<Storefront.Mutation>() {

  @Override public void onResponse(@NonNull final GraphResponse<Storefront.Mutation> response) {
    if (response.data().getCustomerReset().getUserErrors().isEmpty()) {
      String firstName = response.data().getCustomerReset().getCustomer().getFirstName();
      String lastName = response.data().getCustomerReset().getCustomer().getLastName();
    } else {
      Log.e(TAG, "Failed to reset customer");
    }
  }

  @Override public void onFailure(@NonNull final GraphError error) {
    Log.e(TAG, "Failed to execute query", error);
  }
});

A mutation will often rely on some kind of user input. Although you should always validate user input before posting a mutation, there are never guarantees when it comes to dynamic data. For this reason, you should always request the userErrors field on mutations (where available) to provide useful feedback in your UI regarding any issues that were encountered in the mutation query. These errors can include anything from Invalid email address to Password is too short.

Learn more about GraphQL mutations.

Retry

Both QueryGraphCall and MutationGraphCall have an enqueue function that accepts RetryHandler. This object encapsulates the retry state and customization parameters for how the GraphCall will retry subsequent requests (such as after a delay, or a number of retries).

To enable retry or polling:

  1. Create a handler with a condition from one of two factory methods: RetryHandler.delay(long delay, TimeUnit timeUnit) or RetryHandler.exponentialBackoff(long delay, TimeUnit timeUnit, float multiplier).
  2. Provide an optional retry condition for response whenResponse(Condition<GraphResponse<T>> retryCondition) or for error whenError(Condition<GraphError> retryCondition).

If the retryCondition evaluates to true, then the GraphCall will continue to execute the request:

GraphClient graphClient = ...;
Storefront.QueryRootQuery shopNameQuery = ...;

QueryGraphCall call = graphClient.queryGraph(shopNameQuery);

call.enqueue(new GraphCall.Callback<Storefront.QueryRoot>() {

  @Override public void onResponse(GraphResponse<Storefront.QueryRoot> response) {
    ...
  }

  @Override public void onFailure(GraphError error) {
    ...
  }
}, null, RetryHandler.delay(1, TimeUnit.SECONDS)
  .maxCount(5)
  .<Storefront.QueryRoot>whenResponse(response -> response.data().getShop().getName().equals("Empty"))
      .build());
}

The retry handler is generic, and can handle both QueryGraphCall and MutationGraphCall requests equally well.

Errors

There are two types of errors that you need to handle in the response callback:

  • Error returns a list of errors inside GraphResponse, which represent errors related to GraphQL query itself. These should be used

Extension points exported contracts — how you extend this code

GraphCall (Interface)
* * A call to the `GraphQL` server. * * Represents `GraphQL` operation request that has been prepared for execution.
MobileBuy/buy3/src/main/java/com/shopify/buy3/GraphCall.kt
QueryGraphCall (Interface)
* Query `GraphQL` operation call. * * Performs [Storefront.QueryRootQuery] queries that serve [Storefront.QueryRoot] r
MobileBuy/buy3/src/main/java/com/shopify/buy3/GraphCall.kt
MutationGraphCall (Interface)
* Mutation `GraphQL` operation call. * * Performs [Storefront.MutationQuery] queries that serve [Storefront.Mutation]
MobileBuy/buy3/src/main/java/com/shopify/buy3/GraphCall.kt
Node (Interface)
(no doc)
MobileBuy/buy3/src/main/java/com/shopify/graphql/support/Node.java

Core symbols most depended-on inside this repo

get
called by 41
MobileBuy/buy3/src/main/java/com/shopify/graphql/support/AbstractResponse.java
enqueue
called by 27
MobileBuy/buy3/src/main/java/com/shopify/buy3/GraphCall.kt
startField
called by 23
MobileBuy/buy3/src/main/java/com/shopify/graphql/support/Query.java
jsonAsString
called by 20
MobileBuy/buy3/src/main/java/com/shopify/graphql/support/AbstractResponse.java
build
called by 19
MobileBuy/buy3/src/main/java/com/shopify/buy3/GraphClient.kt
appendQuotedString
called by 16
MobileBuy/buy3/src/main/java/com/shopify/graphql/support/Query.java
getFieldName
called by 14
MobileBuy/buy3/src/main/java/com/shopify/graphql/support/AbstractResponse.java
enqueue
called by 8
MobileBuy/buy3/src/main/java/com/shopify/buy3/internal/RealGraphCall.kt

Shape

Method 349
Class 75
Interface 16
Function 9
Enum 1

Languages

Java66%
Kotlin24%
Ruby10%

Modules by API surface

MobileBuy/buy3/src/test/java/com/shopify/graphql/support/Generated.java179 symbols
lib/graphql_java_gen.rb29 symbols
MobileBuy/buy3/src/test/java/com/shopify/graphql/support/IntegrationTest.java25 symbols
MobileBuy/buy3/src/test/java/com/shopify/graphql/support/GeneratedMinimal.java21 symbols
MobileBuy/buy3/src/main/java/com/shopify/buy3/internal/RealGraphCall.kt21 symbols
MobileBuy/buy3/src/main/java/com/shopify/buy3/GraphCall.kt18 symbols
MobileBuy/buy3/src/test/java/com/shopify/buy3/GraphClientTest.kt15 symbols
MobileBuy/buy3/src/main/java/com/shopify/graphql/support/AbstractResponse.java13 symbols
MobileBuy/buy3/src/main/java/com/shopify/buy3/GraphClient.kt12 symbols
MobileBuy/buy3/src/main/java/com/shopify/buy3/RetryHandler.kt10 symbols
MobileBuy/buy3/src/test/java/com/shopify/buy3/NoFileSystem.kt9 symbols
MobileBuy/buy3/src/test/java/com/shopify/buy3/RetryTest.kt8 symbols

For agents

$ claude mcp add mobile-buy-sdk-android \
  -- python -m otcore.mcp_server <graph>

⬇ download graph artifact

Ask about this repo answers extend the page