NAV Navbar
Logo
cURL Python Android Swift Objective-C

Introduction

git clone git@github.com:Mathpix/api-examples.git
cd api-examples/images

Welcome to the Mathpix API! You send us an image, we tell you about the math that’s in it. It’s that simple. We return latex as well as image metadata that you can use in your application. To see examples of images our engine can recognize, see the following link:

We have examples of how to call our API for Shell, Python, Android, and iOS. You can view code examples in the dark area to the right, and you can switch the programming language of the examples with the tabs in the top right.

Note for iOS developers: if you want to integrate Mathpix into your iOS app, there is no easier way than using the Mathpix SDK for iOS: https://github.com/Mathpix/ios-client. With this SDK you can integrate Mathpix into your app with one single line of code without having to implement camera functionality. Also, the UI is fully customizable.

If you have any problems, please send us an email at support@mathpix.com.

Translations

Processing a single image

Call the API as follows:

#!/usr/bin/env python
import sys
import base64
import requests
import json

# put desired file path here
file_path = 'limit.jpg'
image_uri = "data:image/jpg;base64," + base64.b64encode(open(file_path, "rb").read())
# (python3) image_uri = "data:image/jpg;base64," + base64.b64encode(open(file_path, "rb").read()).decode()
r = requests.post("https://api.mathpix.com/v3/latex",
    data=json.dumps({'src': image_uri}),
    headers={"app_id": "trial", "app_key": "34f1a4cea0eaca8540c95908b4dc84ab",
            "Content-type": "application/json"})
print json.dumps(json.loads(r.text), indent=4, sort_keys=True)
curl -X POST https://api.mathpix.com/v3/latex \
    -H 'app_id: trial' \
    -H 'app_key: 34f1a4cea0eaca8540c95908b4dc84ab' \
    -H 'Content-Type: application/json' \
    --data '{ "src": "data:image/jpeg;base64,'$(base64 -i limit.jpg)'" }'
// Using OKHttp
// git url : https://github.com/Mathpix/api-examples/tree/extra/android

OkHttpClient client = new OkHttpClient();

MediaType mediaType = MediaType.parse("application/json");
RequestBody body = RequestBody.create(mediaType, "{ \"src\" : \"data:image/jpeg;base64,{BASE64-STRING}\" }");
Request request = new Request.Builder()
  .url("https://api.mathpix.com/v3/latex")
  .addHeader("content-type", "application/json")
  .addHeader("app_id", "mathpix")
  .addHeader("app_key", "34f1a4cea0eaca8540c95908b4dc84ab")
  .post(body)
  .build();
Response response = client.newCall(request).execute();
Using NSUrl

import Foundation

let headers = [
  "content-type": "application/json",
  "app_id": "mathpix",
  "app_key": "34f1a4cea0eaca8540c95908b4dc84ab"
]
let parameters = ["src": "data:image/jpeg;base64,{BASE64-STRING}"] as [String : Any]

let postData = JSONSerialization.data(withJSONObject: parameters, options: [])

let request = NSMutableURLRequest(url: NSURL(string: "https://api.mathpix.com/v3/latex")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 60.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.httpBody = postData as Data

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()


// Using Alamofire
// git url : https://github.com/Mathpix/api-examples/tree/extra/swift

func processSingleImage(imageName : String) {
        if let data = NSData(contentsOfFile: imageName) {
            let base64String = data.base64EncodedString(options: .init(rawValue: 0))
            let parameters : Parameters = [
                "src" : "data:image/jpeg;base64," + base64String
            ]

            Alamofire.request("https://api.mathpix.com/v3/latex",
                              method: .post,
                              parameters : parameters,
                              encoding: JSONEncoding.default,
                              headers: [
                                "app_id" : "mathpix",
                                "app_key" : "139ee4b61be2e4abcfb1238d9eb99902"
                ])
                .responseJSON{ response in
                if let JSON = response.result.value {
                    print("\(JSON)")
                }
            }
        }
    }
Using NSUrl

#import <Foundation/Foundation.h>

NSDictionary *headers = @{ @"content-type": @"application/json",
                           @"app_id": @"mathpix",
                           @"app_key": @"34f1a4cea0eaca8540c95908b4dc84ab"};
NSDictionary *parameters = @{ @"src": @"data:image/jpeg;base64,{BASE64-STRING}" };

NSData *postData = [NSJSONSerialization dataWithJSONObject:parameters options:0 error:nil];

NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"https://api.mathpix.com/v3/latex"]
                                                       cachePolicy:NSURLRequestUseProtocolCachePolicy
                                                   timeoutInterval:60.0];
[request setHTTPMethod:@"POST"];
[request setAllHTTPHeaderFields:headers];
[request setHTTPBody:postData];

NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request
                                            completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
                                                if (error) {
                                                    NSLog(@"%@", error);
                                                } else {
                                                    NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *) response;
                                                    NSLog(@"%@", httpResponse);
                                                }
                                            }];
[dataTask resume];


// Using AFNetworking
// git url : https://github.com/Mathpix/api-examples/tree/extra/objc

- (void)processSingleImage: (NSString *)imageName {
    NSData *data = [NSData dataWithContentsOfFile:imageName options:NSDataReadingMapped error:nil];
    NSString *base64String = [data base64EncodedStringWithOptions:0];
    NSDictionary *param = @{@"src" : [NSString stringWithFormat:@"data:image/jpeg;base64,%@", base64String]};


    NSMutableURLRequest *request = [[AFJSONRequestSerializer serializer] requestWithMethod:@"POST" URLString:@"https://api.mathpix.com/v3/latex" parameters:param error:nil];
    [request setValue:@"mathpix" forHTTPHeaderField:@"app_id"];
    [request setValue:@"139ee4b61be2e4abcfb1238d9eb99902" forHTTPHeaderField:@"app_key"];

    AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];

    NSURLSessionUploadTask *uploadTask;
    uploadTask = [manager
                  uploadTaskWithStreamedRequest:request
                  progress:^(NSProgress * _Nonnull uploadProgress) {
                      dispatch_async(dispatch_get_main_queue(), ^{
                      });
                  }
                  completionHandler:^(NSURLResponse * _Nonnull response, id  _Nullable responseObject, NSError * _Nullable error) {
                      if (error) {
                          NSLog(@"Error: %@", error);
                      } else { //SUCCESS
                          NSLog(@"Response: %@", responseObject);
                      }
                  }];

    [uploadTask resume];
}

The API returns JSON structured as show here:

{
    "detection_list": [],
    "detection_map": {
        "contains_chart": 0,
        "contains_diagram": 0,
        "contains_geometry": 0,
        "contains_graph": 0,
        "contains_table": 0,
        "is_inverted": 0,
        "is_not_math": 0,
        "is_printed": 0
    },
    "error": "",
    "latex": "\\lim _ { x \\rightarrow 3 } ( \\frac { x ^ { 2 } + 9 } { x - 3 } )",
    "latex_confidence": 0.86757309488734,
    "position": {
        "height": 273,
        "top_left_x": 57,
        "top_left_y": 14,
        "width": 605
    }
}

Request parameters

An API request must contain two headers (app_id and app_key) and a JSON body with a src field that specifies an image as a string either containing a public resource reference to the image content or a data uri containing a base64 encoding of the image. The request body may also contain additional optional fields.

The region field, if present, specifies the image area to process using the properties top_left_x, top_left_y, width, and height, which are all in pixel coordinates (integer valued). For example,

    “region”: {
         “top_left_x”: 0, “top_left_y”: 0, “width”: 10, “height”: 10
    }

specifies a 10 x 10 region at the top left of the image.

The optional ocr field indicates what kinds of content to recognize. The default value is ["math"]. An app that wants to process text should pass ["math", "text"]. Text is returned inside a \text{} environment so that the result can be display using a LaTeX renderer such as MathJax or KaTeX.

The confidence_threshold field, if present, sets the minimum acceptable confidence that the expression is 100% correct. If the expression receives a confidence value lower than this number, the result contains an error field and no latex output.

The confidence_rate_threshold field, if present, sets the minimum acceptable acceptable average per character confidence. This field should be used instead of confidence_threshold in applications where the overall accuracy of the system is more important than the accuracy in recognizing the images in question without a single defect. For example, an auto Latex system is useful even if there are a few characters which are not in it’s vocabulary. As long as the algorithm is generally confident, a few missed characters are acceptable as the user can correct these rapidly.

The formats field, if present, contains an array of one or more strings specifying the desired representations for the results. Accepted representations are latex_normal for the most direct representation of the input, latex_simplified for modifications that assist symbolic processing such as shortening operator names, replacing long division with a fraction, and converting a column of operands into a single formula; latex_styled for modifications to improve the visual appearance such as adding ’\left’ and ’\right’ around parenthesized expressions that contain tall expressions like subscript or superscript; latex_list to split output into a list of simplified strings that assist in processing multiple equations, text to return LaTeX using text mode at the top level instead of math mode, mathml to return a string containing the MathML for the recognized math; and wolfram to return a string that is compatible with the Wolfram Alpha engine. For the mathml and wolfram formats the server will add a mathml_error or wolfram_error field if unable to produce MathML or compatible Wolfram Alpha output from the latex. If formats is not present then the result will contain a latex field with either the latex_normal or latex_simplified representation, depending on the app_key.

Note that an app using the text format must also specify the ocr option as [‘math’,'text’]. The returned string has \text{} removed and \( and \) added around math. For example, if the latex_normal string is \text { The answer is } f ( x ) = 3 x then the result form the text format will be The answer is \( f ( x ) = 3 x \). The text format also flattens simple arrays such as might result from a text paragraph.

For backward compatibility the server also accepts url as an alternative to src and a formats field containing latex, latex_confidence_threshold, and latex_confidence_rate_threshold fields. The result for such requests contains a latex field with the specified latex format.

The skip_recrop field indicates whether Mathpix should skip trying to crop out irrelevant parts of the image. By default, it will not do so. This is to benefit apps for which input images contain lots of noise that should be filtered. If images do not contain noise, skip_recrop should be set to True.

Parameter Description
app_id Application identifier (e.g. mymathsolver)
app_key Application key
content_type application/json
src string
region? {top_left_x, top_left_y, width, height}
ocr? [“math”?, “text”?]
skip_recrop? bool
confidence_threshold? number in [0,1]
confidence_rate_threshold number in [0,1]
formats? string[]

Receiving results

The server responds with the results for the image unless the request contains a callback object, in which case the response only contains a single session_id field and the server asynchronously sends the result to the url specified by callback.post. The asynchronous post contains the result object and a reply object containing the session_id.

An application may override the session_id response by specifying a value for callback.reply in the request. The server will use this value both in the response and the asynchronous post.

Applications that wish to provide additional data in the post may specify a callback.body value. The server will pass this value to the post. If callback.headers is provided then the server will send the contents as headers in the post.

You can create a callback URL for testing simply by visiting https://RequestBin.com/. Sample code to test the async API option are on the right.

To test the async API, replace the callback URL below with your own by visiting https://RequestBin.com/.

#!/usr/bin/env python
import sys
import base64
import requests
import json

file_path = "integral.jpg"
image_uri = "data:image/jpeg;base64," + base64.b64encode(open(file_path, "rb").read())
# (python3) image_uri = "data:image/jpg;base64," + base64.b64encode(open(file_path, "rb").read()).decode()
r = requests.post("https://api.mathpix.com/v3/latex",
    data=json.dumps({'url': image_uri, 'callback': {'post': 'http://RequestBin.com/10z3g561', 'reply': file_path}}),
    headers={"app_id": "trial", "app_key": "34f1a4cea0eaca8540c95908b4dc84ab",
        "Content-type": "application/json"})
print r.text
curl -X POST https://api.mathpix.com/v3/latex \
    -H 'app_id: trial' \
    -H 'app_key: 34f1a4cea0eaca8540c95908b4dc84ab' \
    -H 'Content-Type: application/json' \
    --data '{ "src": "data:image/jpeg;base64,'$(base64 -i integral.jpg)'","callback":{"post": "http://RequestBin.com/10z3g561", "reply": "integral.jpg"}}'

The following JSON is delivered to the callback URL via a POST request:

{
  "reply": "integral.jpg",
  "result": {
    "detection_list": [
      "is_printed"
    ],
    "detection_map": {
      "contains_chart": 0,
      "contains_diagram": 0,
      "contains_geometry": 0,
      "contains_graph": 0,
      "contains_table": 0,
      "is_inverted": 0,
      "is_not_math": 0,
      "is_printed": 1
    },
    "error": "",
    "latex": "\\int \\frac { 4 x } { \\sqrt { x ^ { 2 } + 1 } } d x",
    "latex_confidence": 0.99817252453161,
    "latex_list": [],
    "position": {
      "height": 215,
      "top_left_x": 57,
      "top_left_y": 0,
      "width": 605
    }
  }
}

Results

Example output JSON for the following image is shown on the right.

Confidence values

The API returns confidence scores for the returned latex in the latex_confidence field. It is recommended that you discard results that are below a certain confidence value. You can tune this threshold value for your application. We use a 20% confidence cutoff for our iOS and Android demo apps.

Detection types

The API defines multiple detection types to the client inside the JSON field detection_map. The fields are described below:

Detection Definition
contains_chart Contains a visual representation of a discrete dataset.
contains_table Contains a tabular representation of a discrete dataset.
contains_diagram Contains a diagram.
contains_graph Contains a 1D, 2D, or 3D graph.
contains_geometry Contains chart, table, diagram, or graph.
is_printed The image is taken of printed math, not handwritten math.
is_not_math No valid equation was detected.

The API returns confidence values for each of these detection categories.

Detection coordinates

The position field contains the bounding box of the equation of interest, in pixel coordinates of the image sent. Note that we consider systems of algebraic equations and multiple line equations as single equations. If multiple equations are separated by a lot of text, we will return the first equation only.

Processing a batch of images

A batch request is made as follows:

curl -X POST https://api.mathpix.com/v3/batch \
    -H "app_id: trial" \
    -H "app_key: 34f1a4cea0eaca8540c95908b4dc84ab" \
    -H "Content-Type: application/json" \
    --data '{ "urls": {"inverted": "https://raw.githubusercontent.com/Mathpix/api-examples/master/images/inverted.jpg", "algebra": "https://raw.githubusercontent.com/Mathpix/api-examples/master/images/algebra.jpg"},"callback":{"post": "http://RequestBin.com/sr1x3lsr"}}'

import requests
import json

base_url = 'https://raw.githubusercontent.com/Mathpix/api-examples/master/images/'

data = {
    'urls': {
        'algebra': base_url + 'algebra.jpg',
        'inverted': base_url + 'inverted.jpg'
    },
    'callback': {
        'post': 'http://RequestBin.com/1ftatkr1'
    }
}

r = requests.post(
    "https://api.mathpix.com/v3/batch", data=json.dumps(data),
    headers={
        'app_id': 'trial',
        'app_key': '34f1a4cea0eaca8540c95908b4dc84ab',
        'content-type': 'application/json'
    },
    timeout=30
)
reply = json.loads(r.text)
assert reply.has_key('batch_id')

The callback response is as follows:

{
  "reply": {
    "batch_id": "11"
  }, 
  "result": {
    "algebra": {
      "detection_list": [], 
      "detection_map": {
        "contains_chart": 0, 
        "contains_diagram": 0, 
        "contains_geometry": 0, 
        "contains_graph": 0, 
        "contains_table": 0, 
        "is_inverted": 0, 
        "is_not_math": 0, 
        "is_printed": 0
      }, 
      "error": "", 
      "latex": "12 + 5 x - 8 = 12 x - 10", 
      "latex_confidence": 0.99640350138238, 
      "latex_list": [], 
      "position": {
        "height": 208, 
        "top_left_x": 0, 
        "top_left_y": 0, 
        "width": 1380
      }
    }, 
    "inverted": {
      "detection_list": [
        "is_inverted", 
        "is_printed"
      ], 
      "detection_map": {
        "contains_chart": 0, 
        "contains_diagram": 0, 
        "contains_geometry": 0, 
        "contains_graph": 0, 
        "contains_table": 0, 
        "is_inverted": 1, 
        "is_not_math": 0, 
        "is_printed": 1
      }, 
      "error": "", 
      "latex": "x ^ { 2 } + y ^ { 2 } = 9", 
      "latex_confidence": 0.99982263230866, 
      "latex_list": [], 
      "position": {
        "height": 170, 
        "top_left_x": 48, 
        "top_left_y": 85, 
        "width": 544
      }
    }
  }
}

The Mathpix API supports processing multiple images in a single POST request to a different endpoint: /v3/batch. The request contains urls specifying a key-url pair for each image, and callback that specifies where to send the results. The url in a key-url pair may either be a string or an object containing the url and additional image-specific request parameters such as region and formats. The response contains a unique batch_id value, and after processing all the images the server posts a message to callback.post containing result with a key-result pair for each image result and reply containing the batch_id.

An application may specify a value for callback.reply in the request to include fields in addition to batch_id in both the response and result post. However, the server-generated batch_id cannot be overridden.

Applications that wish to provide additional data in the post may specify a callback.body value. The server will pass this value to the post. If callback.headers is provided then the server will send the contents as headers in the post.

To check on the status of a batch request an application may use GET /v3/batch/:id where :id is the returned batch_id. Note that the GET request must contain the same app_id and app_key headers as the batch request. The response body is JSON containing the batch url keys (array of strings), current results (key-result objects), and the callback object passed to the original batch request. The server only keeps batch results for a limited amount of time after the batch is complete (currently two days but could change in the future).

Long division

{
    "detection_map": {
        "contains_chart": 0,
        "contains_diagram": 0,
        "contains_geometry": 0,
        "contains_graph": 0,
        "contains_table": 0,
        "is_inverted": 0,
        "is_not_math": 0,
        "is_printed": 1
    },
    "latex": "8 \\longdiv { 7200 }"
}

The following <script> tags will take care of rendering the \longdiv markup.

<script type="text/javascript" src="//cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
<script type="text/x-mathjax-config">
    MathJax.Hub.Config({
        tex2jax: {inlineMath: [['$','$'], ['\\(','\\)']]},
        messageStyle: "none",
        TeX: {
            Macros: {
               longdiv: ["{\\overline{\\smash{)}#1}}", 1]
            }
        }
    });
</script>

We use the special markup \longdiv to represent long division; it is the only nonvalid Latex markup we return. Long division is used much like \sqrt which is visually similar.

Latency considerations

The biggest source of latency is image uploads. The speed of a response from Mathpix API servers is roughly proportional to the size of the image. Try to use images under 100kb for maximum speeds. JPEG compression and image downsizing are recommended to ensure lowest possible latencies.

Errors

In addition to the error field that contains a string (en-us locale) describing an error, a Mathpix response has an error_info field with an object providing programmatic information. The fields of this object include id, uniquely specifying the error, message, containing a string similar to the top-level error field, and detail fields specific to the type of error. The table below lists the different errors Mathpix returns.

Id Description Detail fields
http_unauthorized Invalid credentials
http_max_requests Too many requests count
json_syntax JSON syntax error
image_missing Missing URL in request body
image_download_error Error downloading image url
image_decode_error Cannot decode the image data
image_no_content No content found in image
image_not_supported Image is not math or text
image_max_size Image is too large to process
opts_bad_callback Bad callback field(s) post?, reply?, batch_id?
opts_unknown_ocr Unknown ocr option(s) ocr
opts_unknown_format Unknown format option(s) formats
math_confidence Low confidence
math_syntax Unrecognized math
batch_unknown_id Unknown batch id batch_id
sys_exception Server error batch_id?

The two HTTP errors, http_unauthorized and http_max_requests, return HTTP status codes 401 and 429, respectively. All other errors return status 200.

The json_syntax error occurs if the Mathpix server cannot parse the request body. Error ids that begin with “image_” indicate a problem with the image sent, including a request that does not specify an image, a url that cannot be downloaded, image data that cannot be decoded, an image with no recognizable content, an image with unsupported content such as a diagram, or an image that is too large to process. An image_download_error includes a detail field containing the problematic url. Error ids that begin with “opts_” indicate a problem with options in the request body, such as an unknown ocr or format string, or a callback with a bad post, reply, or batch_id field. An opts_bad_callback error includes a detail field for the bad input. Error ids that begin with “math_” indicate either a below-threshold confidence in the recognized LaTeX or a result that is not correct LaTeX syntax.

A GET request on /v3/batch/:id will return a batch_unknown_id error if there is no record of a batch with the given id initiated by a /v3/batch POST using the same credentials. Note this error can occur if the batch was initiated more than a certain period of time (currently two days) before the GET request.

A sys_exception error means the Mathpix server could not correctly process the request. Please report these errors by sending email to support@mathpix.com.

Vocabulary

Mathpix generates any of the following characters:

! $ &
( ) * + ,
- . / 0 1
2 3 4 5 6
7 8 9 : ;
< = > ? A
B C D E F
G H I J K
L M N O P
Q R S T U
V W X Y Z
[ \ ] ^ _
a b c d e
f g h i j
k l m n o
p q r s t
u v w x y
z { | } ~
\% \\ \{ \}
\alpha \angle \langle \rangle \approx
\because \begin{array} \beta \bot \cap
\cdot \cdots \chi \circ \cong
\cup \dagger \Delta \delta \div
\dot \dots \ell \emptyset \eta
\end{array} \epsilon \equiv \exists \kappa
\forall \frac \gamma \Gamma \geq
\hat \hbar \hline \in \infty
\int \Lambda \lambda \lceil \left(
\left. \left[ \left\{ \left| \Leftrightarrow
\leftrightarrow \lfloor \leq \longdiv \mathcal
\mp \mu \nabla \neq \notin
\oint \Omega \omega \operatorna \oplus
\overline \otimes \parallel \partial \perp
\Phi \phi \pi \pm \prime
\prod \propto \Psi \psi \qquad
\quad \rceil \rfloor \rho \right)
\right. \right\} \right] \Rightarrow \rightarrow
\right| \sigma \sim \simeq \sqrt
\square \star \sum \subset \supset
\subseteq \supseteq \tau \text \therefore
\Theta \theta \times \tilde
\varphi \vdots \vec \wedge \vee
\Xi \xi \zeta