# Server-side vs. client-side

**All widgets in CARTO offer the same core functionality**: performant data calculations for large-scale data coming from your Data Warehouse, seamlessly synchronized with your CARTO + deck.gl map.

However, depending on the nature of the [data source](https://docs.carto.com/carto-for-developers/reference/data-sources), the method to perform that calculation can vary:

1. **Server-side calculation**: The widget is calculated by performing SQL queries against your Data Warehouse. This is the most precise and preferred method, and CARTO uses it when available.
2. **Client-side calculation:** The widget is calculated locally, by filtering and aggregating the data that is available in the user's device. This is the fallback method.

## Server-side widget calculation

All `...TableSource` and `...QuerySource` [data source](https://docs.carto.com/carto-for-developers/reference/data-sources) types will work with server-side widget calculation.

{% hint style="success" %}
**No additional setup is required to make server-side widget calculation work.** Your widget will automatically make precise calculations, even for massive data sets or interactive, dynamic aggregations.
{% endhint %}

## Client-side widget calculation

All `...TilesetSource` and `rasterSource` [data source](https://docs.carto.com/carto-for-developers/reference/data-sources) types will work with client-side widget calculation. This type of calculation may have an impact on your application, depending on the following considerations:

{% hint style="warning" %}
**Client-side widgets require:**

* **a @deck.gl/carto tile layer,**
* **A mandatory `spatialFilter` parameter:** learn more about [spatial filters](https://docs.carto.com/carto-for-developers/reference/filters/spatial-filters).
* **plus an additional `loadTiles` configuration step.** In order for your widget to work, you'll need to make sure the local data from your map is loaded into the widget.

```typescript
  const layers = [
    new VectorTileLayer({
      data: dataSource,
      onViewportLoad(tiles) {
        dataSource.widgetSource.loadTiles(tiles); // load tiles when new data is requested
        renderWidgets(); // re-render the widgets with the new data
      }
    })
  ];
```

You can find a fully working example in our [widget-tileset example](https://github.com/CartoDB/deck.gl-examples/tree/master/widgets-tileset).
{% endhint %}

{% hint style="info" %}
**When using client-side widgets, you need to pass your CARTO** [**column-based filters**](https://docs.carto.com/carto-for-developers/reference/filters/column-filters) **to each widget model**

```typescript
const layers = [
  new VectorTileLayer({
    data: dataSource,
    onViewportLoad(tiles) {
      dataSource.widgetSource.loadTiles(tiles); // load tiles when new data is requested
      renderWidgets(); // re-render the widgets with the new data
    },
    // Optional filtering for the layer
    extensions: [new DataFilterExtension()],
    ...getDataFilterExtensionProps(filters, 'and', 2)
  })
];

// filtered widget  
const histogram = await dataSource.widgetSource.getHistogram({
  column: 'streamOrder',
  ticks: histogramTicks,
  operation: 'count',
  filters: myFilter,
  spatialFilter: viewportSpatialFilter
});
```

{% endhint %}

{% hint style="warning" %}
**Client-side widgets can be less precise in certain scenarios.** When using tilesets or rasters, there are different scenarios that can interfere with your widgets calculations:

1. **Tilesets with feature dropping at lower zoom levels:** In order to keep visualizations performant, tilesets generated from large data sets will drop features in the lower zoom levels, when covering a larger area. When calculating widgets client-side, the features dropped won't be available. You can detect the amount of *feature dropping* for a specific tileset and zoom level by inspecting the `...TilesetSource` response. You can inspect how we handle it in our [widget-tileset example](https://github.com/CartoDB/deck.gl-examples/tree/master/widgets-tileset).
2. **Raster pyramids with aggregation at lower zoom levels:** Raster pyramids (composed of different raster layers for different zoom levels) will typically have a larger raster pixel size in lower zoom levels, when covering a larger area. In those cases, the client-side calculations of raster widgets can be less precise. You can adapt your app to this scenario by understanding your raster metadata, like we do in our [widgets-raster example](https://github.com/CartoDB/deck.gl-examples/tree/master/widgets-raster).
3. **Tiles not loaded by the layer (e.g. far offscreen) are not included in calculations:** Even if your `spatialFilter` parameters covers a greater surface than the current map view state, tiles that aren't currently loaded by the layer will not be included in the widget
   {% endhint %}

{% hint style="success" %}
**By default, client-side widgets perform its calculations using background threads powered by** [**Web Workers**](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers)**.** This enhances perceived performance of the application by keeping the application fluid and running even when performing intensive calculations.

If your stack or application is not compatible with Web Workers, you can disable them at the [data source](https://docs.carto.com/carto-for-developers/reference/data-sources) level using the `widgetWorker: false` property.
{% endhint %}
