> ## Documentation Index
> Fetch the complete documentation index at: https://developer.dromo.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Handling Results

## The `onResults` callback[​](#the-onresults-callback "Direct link to the-onresults-callback")

This callback is called when the user completes the import flow. `onResults` is called with two arguments.

<CodeGroup>
  ```js JavaScript theme={null}
  dromo.onResults(function (response, metadata) {  // Do something with the data here  console.log(response, metadata);});
  ```

  ```jsx React theme={null}
  <DromoUploader  ...  onResults={(response, metadata) =>    // Do something with the data here    console.log(response, metadata)  }>  Launch Dromo</DromoUploader>
  ```
</CodeGroup>

<ResponseField name="data" type="{ [key: string]: string | boolean | number | null }[]">
  An array of objects, one for each row in the final data.

  The keys of each object will be the field keys of each mapped field, and the values will be the final value of that field, based on the field's type.

  **Note: If a field is [`manyToOne`](/reference/fields/field-types#manytoone), the value will be an array.**
</ResponseField>

<ResponseField name="metadata" type="object">
  <ResponseField name="id" type="string | null">
    Dromo assigns a unique ID to each completed import that is synced to the backend. This ID can be used to retrieve the import from the [Dromo API](/api-reference).

    If [`backendSyncMode`](/reference/settings/settings#backendsyncmode) is `"DISABLED"`, the import ID will be `null`.
  </ResponseField>

  <ResponseField name="filename" type="string | null">
    The filename of the file that the user uploaded.

    `null` if the user did not upload a file (i.e. used manual entry).
  </ResponseField>

  <ResponseField name="importIdentifier" type="string">
    The [`importIdentifier`](/reference/settings/settings#importidentifier) of this import
  </ResponseField>

  <ResponseField name="user" type="User">
    The [user](/reference/users) associated with this import
  </ResponseField>

  <ResponseField name="rowsWithError" type="number[]">
    Array of row indices where at least one error appears.
  </ResponseField>

  <ResponseField name="errors" type="{ rowIndex: number, fieldKey: string, message: string, value: string }[]">
    Array of objects detailing all the errors in the upload.
  </ResponseField>

  <ResponseField name="fields" type="object">
    An object whose keys are the field keys and values are objects containing metadata about that field

    <ResponseField name="fileHeader" type="string | null">
      The header this field was mapped to. `null` if no file was uploaded.
    </ResponseField>

    <ResponseField name="fileHeaderIndex" type="number | null">
      The column header index this field was mapped to. `null` if no file was uploaded.
    </ResponseField>

    <ResponseField name="isCustom" type="boolean">
      Whether this field was added by the user as a custom field
    </ResponseField>

    <ResponseField name="manyToOne" type="boolean">
      Indicates if this field is [manyToOne](/reference/fields/field-types#manytoone).
    </ResponseField>

    <ResponseField name="fileHeaders" type="string[]">
      The headers that were mapped to the field if it is [manyToOne](/reference/fields/field-types#manytoone).
    </ResponseField>

    <ResponseField name="fileHeaderIndexes" type="number[]">
      The indexes of columns that were mapped to a [manyToOne](/reference/fields/field-types#manytoone) field.
    </ResponseField>
  </ResponseField>
</ResponseField>

## The `onCancel` callback[​](#the-oncancel-callback "Direct link to the-oncancel-callback")

This callback is called if the user exits from the import without completing it.

`onCancel` does not receive any arguments.

## The `beforeFinish` callback[​](#the-beforefinish-callback "Direct link to the-beforefinish-callback")

Sometimes, you may wish to perform validation on the final result data before the user leaves the import.

To accomplish this, you can define a `beforeFinish` callback. This callback will fire when the user finishes the import, and receives the same arguments as the `onResults` callback. The callback also receives a third argument, `instance`, with the instance of the uploader.

If you define a `beforeFinish` callback, you can cancel finishing the upload by returning an object in the format `{ cancel: true, message: "Message to user" }`. In this case, the user will remain on the Review Screen, with the given error message shown to the user. The `onResults` callback will not fire and the import will not complete. This process will repeat the next time the user submits the import.

Otherwise, if nothing is returned from the `beforeFinish` callback (or any other value is returned), the `onResults` callback will fire and the import will complete normally.

<ResponseField name="data" type="{ [key: string]: string | boolean | number | null }[]">
  An array of objects, one for each row in the final data.

  The keys of each object will be the field keys of each mapped field, and the values will be the final value of that field, based on the field's type.
</ResponseField>

<ResponseField name="metadata" type="object">
  <ResponseField name="filename" type="string | null">
    The filename of the file that the user uploaded.

    `null` if the user did not upload a file (i.e. used manual entry).
  </ResponseField>

  <ResponseField name="importIdentifier" type="string">
    The [`importIdentifier`](/reference/settings/settings#importidentifier) of this import
  </ResponseField>

  <ResponseField name="user" type="User">
    The [user](/reference/users) associated with this import
  </ResponseField>

  <ResponseField name="rowsWithError" type="number[]">
    Array of row indices where at least one error appears.
  </ResponseField>

  <ResponseField name="errors" type="{ rowIndex: number, fieldKey: string, message: string, value: string }[]">
    Array of objects detailing all the errors in the upload.
  </ResponseField>

  <ResponseField name="fields" type="object">
    An object whose keys are the field keys and values are objects containing metadata about that field

    <ResponseField name="fileHeader" type="string | null">
      The header this field was mapped to. `null` if no file was uploaded.
    </ResponseField>

    <ResponseField name="fileHeaderIndex" type="number | null">
      The column header index this field was mapped to. `null` if no file was uploaded.
    </ResponseField>

    <ResponseField name="isCustom" type="boolean">
      Whether this field was added by the user as a custom field
    </ResponseField>

    <ResponseField name="manyToOne" type="boolean">
      Indicates if this field is [manyToOne](/reference/fields/field-types#manytoone).
    </ResponseField>

    <ResponseField name="fileHeaders" type="string[]">
      The headers that were mapped to the field if it is [manyToOne](/reference/fields/field-types#manytoone).
    </ResponseField>

    <ResponseField name="fileHeaderIndexes" type="number[]">
      The indexes of columns that were mapped to a [manyToOne](/reference/fields/field-types#manytoone) field.
    </ResponseField>
  </ResponseField>
</ResponseField>

<ResponseField name="instance" type="DromoUploader">
  The Dromo Uploader instance which you can call mutation methods on
</ResponseField>

<CodeGroup>
  ```js JavaScript theme={null}
  dromo.beforeFinish(function (data, metadata, instance) {  if (data.length < 20) {    return { cancel: true, message: "You must import at least 20 rows" }  }});
  ```

  ```jsx React theme={null}
  <DromoUploader  ...  beforeFinish={(data, metadata, instance) =>    if (data.length < 20) {      return { cancel: true, message: "You must import at least 20 rows" }    }  }>  Launch Dromo</DromoUploader>
  ```
</CodeGroup>

## Custom fields[​](#custom-fields "Direct link to Custom fields")

If you have enabled [`allowCustomFields`](/reference/settings/settings#allowcustomfields), it will allow the user to add custom fields that are not part of the field schema. The name of the custom field will be added as a key to the result objects.

As an example, if the user defines a column name "fav\_color", the response would look like the following:

```
{  "name": "Jack",  "email_address": "jack@thehill.com",  "fav_color": "blue"}
```
