Upload Source Maps to Sentry

Sentry is a widely used error monitoring platform that tracks bugs or errors happening in a variety of applications. Among other pieces of information, it captures error stack traces which are essential for developers to figure out the source of the issue.

The code obfuscation makes your error stack traces very difficult for your developers to understand where the bug comes from. Thus, we can take advantage of Jscrambler source maps and Sentry's source-map upload feature to make stack traces readable.

This page explains how to upload Jscrambler source maps to the Sentry platform using a React application.

Example React App

For the purposes of this tutorial, we will be using a create-react-app boilerplate app.

npx create-react-app my-app
cd my-app

For further information check the create-react-app Getting Started Guide.

Integrating Jscrambler with React

If you haven't tried Jscrambler out before reading this tutorial, please consider reading the Getting Started Guide which will walk you through the steps on how to protect your application. This will make this section easier to grasp. It will also teach you how to configure Jscrambler and use a custom configuration.

To complete the integration with Jscrambler, you need a JSON configuration file with your API credentials, application ID, and protection configuration. You may create your transformations recipe using Jscrambler Web application and download a JSON configuration file or use the following example for a quick test. This file should be named .jscramblerrc and placed in the project's root folder. If you choose to try the following example, just make sure to fill in the missing information: accessKey, secretKey and applicationId.

{
 "keys": {
   "accessKey": <ACCESS_KEY_HERE>,
   "secretKey": <SECRET_KEY_HERE>
 },
 "applicationId": <APP_ID_HERE>,
 "filesSrc": [
   "./build/**/*.html",
   "./build/**/*.js",
   "./build/**/*.js.map"
 ],
 "cwd": "./build",
 "filesDest": "./build",
 "params": [
   {
      "name": "objectPropertiesSparsing"
    },
    {
      "name": "variableMasking"
    },
    {
      "name": "whitespaceRemoval"
    },
    {
      "name": "dotToBracketNotation"
    },
    {
      "name": "stringConcealing"
    },
    {
      "name": "functionReordering"
    },
    {
      "name": "propertyKeysObfuscation",
      "options": {
        "encoding": [
          "hexadecimal"
        ]
      }
    },
    {
      "name": "regexObfuscation"
    },
    {
      "name": "controlFlowFlattening",
      "options": {
        "features": [
          "opaqueSteps"
        ]
      }
    },
    {
      "name": "booleanToAnything"
    },
    {
      "name": "identifiersRenaming"
    },
    {
      "name": "globalVariableIndirection"
    }
 ],
 "areSubscribersOrdered": false,
 "useRecommendedOrder": true,
 "sourceMaps": true,
 "jscramblerVersion": "stable"
}

You can also change filesSrc to match the files you need/want to protect. For our example — and all React apps — we recommend protecting the .html and .js files. Certainly, with a better understanding of the project, you may identify what’s critical and essential to protect.

Notice that the filesSrc also includes the source-maps ("./build/**/*.js.map") generated by the create-react-app tool which tells Jscrambler engine that a previous transformation (f.e. bundling) already take place and should be taken in account.

By using filesDest: './build' and cwd: build, the files we send to protect will be overwritten by their protected version using build as the working directory.

The sourceMaps: true instructs Jscrambler to produce source maps for this application.

Integrating Jscrambler in the Build Process

You can integrate Jscrambler into the React build process with the CLI.

Install the Jscrambler API Client:

npm install jscrambler --save-dev

Create a CLI hook in the scripts section of package.json. The section should look like this:

"scripts": {
  "start": "react-scripts start",
  "build": "react-scripts build && jscrambler",
  "test": "react-scripts test",
  "eject": "react-scripts eject"
},

The "build": "react-scripts build && jscrambler" hook will trigger the jscrambler command after the build process is finished.

Jscrambler is now integrated into your build process and the protected production files will be placed on build/static/.

Set up Sentry

Sentry's account is mandatory

Log into your Sentry account, create (if you don't already have one) a project and follow the set up instructions.

In case of an React Application, you should:

  • Install the @sentry/react dependency
npm install @sentry/react --save
  • Initialize Sentry as early as possible in your application's lifecycle. Please, add the following code in src/index.js file:
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
// ADD import sentry
import * as Sentry from '@sentry/react';

// ADD initialize Sentry
Sentry.init({
  // <DSN_URL> can be found in the project settings on the Client Keys (DSN) section 
  dsn: "https://<DSN_URL>",
});

// rest of the code
  • Create an upload source-maps script on package.json using @sentry/wizard
## When asked for "Which framework, bundler or build tool are you using?" select "Create React App"
## When asked for "Where are your build artifacts located?" type "build" 
## When asked for "Do you want to automatically run the sentry:sourcemaps script after each production build?" select "No" 
npx @sentry/wizard@latest -i sourcemaps

Intentional Error

To produce an intentional error event on Sentry, please add the following button to the file src/App.js

        <a
          className="App-link"
          href="https://reactjs.org"
          target="_blank"
          rel="noopener noreferrer"
        >
          Learn React
        </a>
        {/* add next line */}  
        <button onClick={(e) => e.methodDoesNotExist()}>Break the world</button>

Build the application:

npm run build

Download Jscrambler Source maps

Use Jscrambler api client to download the corresponding source maps for a specific protection.

The protection-id is printed on the console as the last entry after the npm run build script run successfully (f.e. 64cbb11def19a471ff6df88c)

jscrambler -m <protection id> -o ./

On the project root, you should see a folder called jscramblerSourceMaps containing the generated source-maps.

Now, we updated the application source-maps with Jscrambler ones

cp -r jscramblerSourceMaps/* build 

Upload Source maps to Sentry

Run the sentry:sourcemaps script

npm run sentry:sourcemaps

On the Source Map Upload Report you should be able to see what was uploaded to the Sentry platform

Trigger an Error event

Finally, we can run our application by spinning a web server pointing to the build folder. You can use server by typing:

npm i -g serve
serve -s build

Open a browser and navigate to the address allocated by the serve tool (f.e. http://localhost:3000).

Once the page is loaded, hit on the Break the world button, and you should see an error displayed on the browser's console.

Intentional Error

Now, let's check the Sentry Issues page and you should see the error event we just triggered.

Sentry Issues Page

Navigate to the details of the error event, and in the Stack Trace section, you will see where the error occurred in the original source code.

Sentry Error Event Details

Thanks to Jscrambler Source-maps and Sentry, your development team can quickly identify the bugs and errors that happened in your application.