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

# Virtual Columns

> Create new columns by applying custom data transformation logic.

**Virtual Columns** are one of CSVbox's most powerful data transformation tools. They run small snippets of JavaScript that **merge**, **split**, **re-format**, **correct**, and **enrich** incoming data during an import.

Use them to process your data, do calculations, or merge values together before the data reaches your end.

## How it works

<Steps>
  <Step title="Add a virtual column">
    For any sheet (template), add a virtual column in the CSVbox dashboard.
  </Step>

  <Step title="Attach a JavaScript snippet">
    Attach a JavaScript snippet to the virtual column.
  </Step>

  <Step title="Users submit the CSV file">
    After users submit the CSV file, the JavaScript runs to populate data in the virtual columns.
  </Step>

  <Step title="Data is pushed to the destination">
    Data from the uploaded CSV and the virtual columns is pushed to the data destination.
  </Step>
</Steps>

### Example

<Tabs>
  <Tab title="Merge">
    Merge data from the `first_name` and `last_name` columns into a new virtual column named `full_name`.

    Here is the JavaScript attached to the `full_name` virtual column:

    ```javascript theme={null}
    try
    {
    	return csvbox.row["first_name"] + ' ' + csvbox.row["last_name"];
    }
    catch(err)
    {
      	return 'error: ' + err.name + ' | ' + err.message;
    }
    ```
  </Tab>

  <Tab title="Re-format">
    Normalize the incoming `order_date` into UTC format.

    ```javascript theme={null}
    try
    {  	const date = new Date(csvbox.row["order_date"]);

    	return date.toUTCString();
    }
    catch(err)
    {
      	return 'error: ' + err.name + ' | ' + err.message;
    }
    ```
  </Tab>

  <Tab title="Static">
    Pass any static value to the virtual column.

    ```javascript theme={null}
    try
    {
    	return 'Amazon';
    }
    catch(err)
    {
      	return 'error: ' + err.name + ' | ' + err.message;
    }
    ```
  </Tab>
</Tabs>

## Adding virtual columns

<Steps>
  <Step title="Open the Columns tab">
    Go to the edit sheet page → **Columns** tab, and click the **Add Virtual Column** button.
  </Step>

  <Step title="Name the column">
    Add the virtual **Column Name**.
  </Step>

  <Step title="Provide the JavaScript code">
    Enter the **Javascript** code.
  </Step>

  <Step title="Attach dependencies (optional)">
    Attach **Dependent** libraries.
  </Step>

  <Step title="Save the column">
    Click **Save**.
  </Step>
</Steps>

<Frame caption="Add Virtual Column">
  <img src="https://mintcdn.com/csvbox-io/gyjvlPdP5mzE2jo9/images/add-virtual-column.jpg?fit=max&auto=format&n=gyjvlPdP5mzE2jo9&q=85&s=4190e7195a9e16d86f3a3da75e42c9e8" alt="Add Virtual Column dialog" width="1052" height="768" data-path="images/add-virtual-column.jpg" />
</Frame>

## Data rows

Data rows are the core object that virtual columns are built around. For each incoming CSV data row, you can read its data and manipulate it with JavaScript to populate the virtual column.

After the user submits the CSV, the JavaScript runs for each data row in sequential order to populate the virtual columns.

Use the `csvbox.row` object to work with each row, and `csvbox.row["column_name"]` to read a specific column of the data row. You can use data from a single column, multiple columns, or no columns to populate virtual columns.

## Inserting data into virtual columns

The value returned by the JavaScript snippet is added to the virtual column.

```javascript theme={null}
// Extracting first name
try
{  	var fullName = csvbox.row["full_name"].split(' ');

	// returning value
	return  fullName[0];
}
catch(err)
{
	//returning error
  	return 'error: ' + err.name + ' | ' + err.message;
}
```

<Note>
  If the JavaScript returns a `NULL` value, an empty string is added to the virtual column.
</Note>

## Receiving virtual data

Virtual column data is available at all data destinations along with the data from the regular columns.

<Tabs>
  <Tab title="API/Webhook, Zapier, etc.">
    In the API response JSON object, the virtual data appears inside the `_virtual_data` object, as shown below. The `_virtual_data` object is visible only if virtual columns are added to the sheet. In the example below, check lines 12 and 31.

    ```json lines theme={null}
    [
      {
        "import_id": 79418895,
        "sheet_id": 55,
        "sheet_name": "Products",
        "row_number": 1,
        "row_data": {
              "Name": "TP-Link TL-WN822N Wireless Adapter",
              "SKU": "AS-100221",
              "Price": "33.00",
              "Quantity": "3",
              "_virtual_data":{
    		"SKU_prefix": "AS",
    		"Compare_Price": "43.00"
               }
        },
        "custom_fields": {
          "user_id": "1002"
        }
      },
      {
        "import_id": 79418895,
        "sheet_id": 55,
        "sheet_name": "Products",
        "row_number": 2,
        "row_data":{
              "Name": "EPower EP-600PM Power Supply Cooling Fan",
              "SKU": "SS-103824",
              "Price": "95.35",
              "Quantity": "8",
               "_virtual_data":{
    		"SKU_prefix": "SS",
    		"Compare_Price": "105.35"
               }
            },
        "custom_fields": {
          "user_id": "1002"
        }
      },
    ]
    ```
  </Tab>

  <Tab title="MySQL, Bubble, Airtable etc">
    Virtual columns are available in the column mapping modal. You can push virtual columns to any receiving data field of your choice.

    <Frame caption="Mapping Virtual Columns">
      <img src="https://mintcdn.com/csvbox-io/Fn747PbJ5U7GCAW2/images/virtual-col-mapping.jpg?fit=max&auto=format&n=Fn747PbJ5U7GCAW2&q=85&s=4a9d45951be1d65014e8ccf058681fad" alt="Mapping virtual columns to destination fields" width="504" height="528" data-path="images/virtual-col-mapping.jpg" />
    </Frame>
  </Tab>

  <Tab title="S3, FTP etc">
    In the AWS S3 file store, virtual columns are added as new columns in the uploaded file.
  </Tab>
</Tabs>

The virtual data is also available on the [client-side JSON object](/getting-started/3-receive-data#data-on-the-client-side).

## Dependencies

In the JavaScript snippet, you can use an external library hosted on a CDN. You can also call any external API endpoint to fetch real-time data. Add the library script tag and any custom scripts to the **Dependencies** section, then use them in the main JavaScript snippet.

For each import, the dependent scripts run only once, whereas the main JavaScript snippet runs once for each row.

<Frame caption="Virtual Column Processing">
  <img src="https://mintcdn.com/csvbox-io/DJwuudNXVbQXa5C2/images/virtualcolumnprocessing.png?fit=max&auto=format&n=DJwuudNXVbQXa5C2&q=85&s=860b0f8f50959c5e0d0f9978efacd0b0" alt="Virtual column processing: dependencies run once, the snippet runs per row" width="2240" height="680" data-path="images/virtualcolumnprocessing.png" />
</Frame>

<Accordion title="Example">
  Suppose you want to use the data from the incoming `USD_amount` column to create a new `GBP_amount` virtual column. The amount should be converted from USD to GBP using real-time exchange rates.

  You can use the [Money.js](https://github.com/openexchangerates/money.js) library for currency conversions and [Open Exchange Rates](https://openexchangerates.org/) to fetch real-time conversion rates. Here is the sample dependency code:

  ```javascript Dependent Scripts theme={null}
  //Load jQuery via CDN
  <script src="https://code.jquery.com/jquery-3.6.1.min.js" integrity="sha256-o88AwQnZB+VDvE9tvIXrMQaPlFFSUTR+nldQm1LuPXQ=" crossorigin="anonymous"> </script>

  //Load Money.js via CDN
  <script src="https://cdnjs.cloudflare.com/ajax/libs/money.js/0.0.1/money.min.js" integrity="sha512-dfZQaBBlTXvL+AUQKi7dd/9kb/KhreymnZYVdinjigqTdZUrAnLUNJRV34DUPFCdyek9mMBns3rzTlipnBKhTg==" crossorigin="anonymous" referrerpolicy="no-referrer"> </script>

  //Fetch real-time conversion rates via ajax call and initialize fx object
  <script type="text/javascript" >

      // Load exchange rates data via AJAX:
      $.getJSON(
          // NB: using Open Exchange Rates here, but you can use any source!
          'https://openexchangerates.org/api/latest.json?app_id=fa4744d77e844adb9cc3533b7ae162f3',
          function(data) {
              // Check money.js has finished loading:
              if (typeof fx !== "undefined" && fx.rates) {
                  fx.rates = data.rates;
                  fx.base = data.base;
              } else {
                  // If not, apply to fxSetup global:
                  var fxSetup = {
                      rates: data.rates,
                      base: data.base
                  }
              }
          }
      );
  </script>
  ```

  Corresponding JavaScript snippet for the `GBP_amount` virtual column:

  ```javascript Javascript snippet theme={null}
  try
  {
  	//USD to GBP
  	return fx.convert(csvbox.row["USD_amount"], {from: "USD", to: "GBP"});

  }
  catch(err)
  {
  	//returning error
    	return 'error: ' + err.name + ' | ' + err.message;
  }
  ```
</Accordion>

## Variables

In the virtual column JavaScript snippet, you have access to data variables in the `csvbox` object. The following data is available:

<a id="csvboxrow" style={{ scrollMarginTop: "var(--scroll-mt, 7rem)" }} />

### `csvbox.row`

Contains the row data. Access each cell in the row by providing the column name. Examples:

```javascript theme={null}
csvbox.row["first_name"]
csvbox.row["order_id"]
csvbox.row["price"]
```

<Warning>
  The column name must exist on the sheet, or an error is thrown.
</Warning>

### `csvbox.user`

Contains the [custom user attributes](/getting-started/2-install-code#referencing-the-user) defined while initializing the importer. Examples:

```javascript theme={null}
csvbox.user["user_id"]
csvbox.user["team_id"]
csvbox.user["isAuthenticated"]
```

### `csvbox.import`

Contains data specific to the current import. The following data is available:

```javascript theme={null}
csvbox.import["sheet_id"]
csvbox.import["sheet_name"]
csvbox.import["original_filename"]
csvbox.import["import_start_time"]
csvbox.import["destination_type"]
csvbox.import["total_rows"]
csvbox.import["row_number"] //current row number starting with 1
```

<a id="csvboxvirtual" style={{ scrollMarginTop: "var(--scroll-mt, 7rem)" }} />

### `csvbox.virtual`

Contains data from the preceding virtual columns.

```javascript theme={null}
csvbox.virtual["final_name"]
csvbox.virtual["age"]
```

<Warning>
  Only data from the virtual columns defined before the current virtual column is available for use.
</Warning>

<a id="csvboxenvironment" style={{ scrollMarginTop: "var(--scroll-mt, 7rem)" }} />

### `csvbox.environment`

Contains the [environment variables](/advanced-installation/environment-variables) passed during importer initialization.

```javascript theme={null}
// Example Usage
if(csvbox.environment["user_id"] && csvbox.environment["user_id"] == "abc123") {

 // code

}
```

<Tip>
  Use `console.log(csvbox);` to print all the available variables in the debugging console.
</Tip>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.