Last updated

Files SDK

The Files SDK provides tools for integrating Fluid's Digital Asset Management (DAM) capabilities into your applications.

Installation

npm install @fluid-app/dam-picker

Quick Start

import { DamPicker } from '@fluid-app/dam-picker';

const picker = new DamPicker({
  token: 'pub-your-public-token',
  onSelect: (result) => {
    console.log('Selected:', result.asset.url);
  },
});

picker.open();

Authentication

The SDK requires a public token (pub- prefix) created via the Public Tokens API. Server-side tokens (C-, PT-, dit-, cdt-, U-) are blocked for security.

Public tokens without a domain allowlist must have an expiration and should be generated server-side on each page load. Tokens with a domain allowlist can live without expiration. See the Authentication Guide for details on token expiration, domain allowlists, and available scopes.

Configuration

Full Options Reference

OptionTypeDefaultDescription
tokenstringRequired. Public token (pub- prefix) or JWT
acceptstring[]All typesFile type restrictions — MIME types or extensions
fromSourcesSourceId[]All sourcesWhich source tabs to show
transformationsobject | falseAll enabledTransformation tools to enable, or false to skip
maxFilesnumber1Maximum files the user can select
minFilesnumber1Minimum files required before confirming
maxSizenumberNo limitMaximum file size in MB
imageDim[width, height]Force exact image dimensions
imageMax[width, height]Maximum image dimensions
imageMin[width, height]Minimum image dimensions
assetAssetInputPre-load a single asset — skips picker, opens transforms
assetsAssetInput[]Pre-load multiple assets for transformation
zIndexnumber10000Z-index of the modal overlay
onSelect(result) => voidRequired. Called when user confirms selection
onCancel() => voidCalled when user closes without selecting
onError(error) => voidCalled when an error occurs
onReady() => voidCalled when the picker has loaded and is ready

File Type Filtering (accept)

Control which file types users can upload and browse using MIME types or file extensions:

// Images only
{ accept: ['image/*'] }

// Videos only
{ accept: ['video/*'] }

// PDF documents only
{ accept: ['application/pdf'] }

// Images and PDFs
{ accept: ['image/*', 'application/pdf'] }

// SVG files only
{ accept: ['.svg'] }

// Audio files only
{ accept: ['audio/*'] }

Source Tabs (fromSources)

Control which acquisition sources appear as tabs. Available sources:

Source IDTab LabelDescription
local_file_systemUploadUpload from the user's computer
urlURLImport from a URL
dam_libraryLibraryBrowse the company's DAM library
unsplashStockSearch Unsplash stock photos
ai_generateGenerateAI image generation
// Upload and library only
{ fromSources: ['local_file_system', 'dam_library'] }

// External sources only
{ fromSources: ['url', 'unsplash'] }

// Single file upload (no browsing)
{ fromSources: ['local_file_system'] }

// All sources (default)
{ fromSources: ['local_file_system', 'url', 'dam_library', 'unsplash', 'ai_generate'] }

Transformations

The picker includes built-in image transformation tools. Control which tools appear, or disable transformations entirely:

ToolKeyDescription
CropcropCrop with aspect ratio presets
RotaterotateRotate left/right
QualityqualityQuality selector (Very Low to Full)
Remove BackgroundremoveBackgroundAI-powered background removal
Change BackgroundchangeBackgroundAI: Replace background with a text prompt
UpscaleupscaleAI: Increase image resolution
RetouchretouchAI: Enhance and retouch image
Drop ShadowdropShadowAI: Add realistic drop shadow
Smart CropsmartCropAI: Auto-focus crop on subject
Edit with AIeditWithAiAI: Edit image with a text prompt
// All transformations enabled (default)
{ transformations: { crop: true, rotate: true, quality: true, removeBackground: true, changeBackground: true, upscale: true, retouch: true, dropShadow: true, smartCrop: true, editWithAi: true } }

// Only crop and rotate
{ transformations: { crop: true, rotate: true, quality: false, removeBackground: false, changeBackground: false, upscale: false, retouch: false, dropShadow: false, smartCrop: false, editWithAi: false } }

// Only AI tools (no manual crop/rotate)
{ transformations: { crop: false, rotate: false, quality: false } }

// Skip transformations entirely
{ transformations: false }

Selection Limits

// Single select (default)
{ maxFiles: 1 }

// Multi-select up to 5
{ maxFiles: 5 }

// Require at least 2, up to 4
{ minFiles: 2, maxFiles: 4 }

File Size Limits

// Max 5 MB
{ maxSize: 5 }

// Max 1 MB, images only
{ maxSize: 1, accept: ['image/*'] }

Image Dimension Constraints

// Exact dimensions (800x600)
{ imageDim: [800, 600] }

// Maximum dimensions (1920x1080)
{ imageMax: [1920, 1080] }

// Minimum dimensions (400x400)
{ imageMin: [400, 400] }

Common Presets

Hero Image

const picker = new DamPicker({
  token: 'pub-xxxxx',
  accept: ['image/*'],
  maxSize: 10,
  imageMin: [1200, 600],
  maxFiles: 1,
  onSelect: (result) => setHeroImage(result.asset.url),
});
const picker = new DamPicker({
  token: 'pub-xxxxx',
  accept: ['image/*'],
  maxSize: 5,
  imageMin: [400, 400],
  minFiles: 3,
  maxFiles: 8,
  onSelect: (result) => setGalleryImages(result.assets.map(a => a.url)),
});

Avatar / Profile Picture

const picker = new DamPicker({
  token: 'pub-xxxxx',
  accept: ['image/*'],
  maxSize: 2,
  imageMin: [200, 200],
  fromSources: ['local_file_system', 'url'],
  maxFiles: 1,
  onSelect: (result) => setAvatar(result.asset.url),
});

Document Upload

const picker = new DamPicker({
  token: 'pub-xxxxx',
  accept: ['application/pdf'],
  maxSize: 25,
  maxFiles: 5,
  fromSources: ['local_file_system', 'url'],
  transformations: false,
  onSelect: (result) => attachDocuments(result.assets),
});

Background Removal Only

const picker = new DamPicker({
  token: 'pub-xxxxx',
  accept: ['image/*'],
  transformations: {
    crop: true,
    rotate: false,
    quality: false,
    removeBackground: true,
    changeBackground: false,
    upscale: false,
    retouch: false,
    dropShadow: false,
    smartCrop: false,
    editWithAi: false,
  },
  onSelect: (result) => setProductImage(result.asset.url),
});

Transform Mode

Skip the picker entirely and open an existing asset directly in the transformation editor:

const picker = new DamPicker({
  token: 'pub-xxxxx',
  asset: { url: 'https://ik.imagekit.io/fluid/your-company/image.jpg' },
  onSelect: (result) => {
    console.log('Transformed:', result.asset.url);
  },
  onCancel: () => console.log('Cancelled'),
});

picker.open();

You can also pass an asset code instead of a URL:

{ asset: { assetCode: 'ABC123' } }

Or both:

{ asset: { url: 'https://...', assetCode: 'ABC123', name: 'My Image' } }

Result Object

When a user makes a selection, onSelect receives a DamPickerResult:

interface DamPickerResult {
  /** The first (or only) selected asset */
  asset: SelectedAsset;
  /** All selected assets (always an array, even for single-select) */
  assets: SelectedAsset[];
}

interface SelectedAsset {
  url: string;           // Public URL
  assetCode: string;     // Unique asset identifier
  name: string;          // Display name
  mimeType: string;      // e.g. "image/png", "video/mp4"
  variantId?: string;    // ID of the selected variant
  metadata?: {
    width?: number;
    height?: number;
    fileSize?: number;
  };
}

Example: Using the Result

onSelect: (result) => {
  // Single select — use result.asset
  const { url, assetCode, mimeType } = result.asset;
  document.querySelector('img').src = url;

  // Multi-select — iterate result.assets
  result.assets.forEach((asset) => {
    console.log(`${asset.name}: ${asset.url}`);
  });

  // Check dimensions
  if (result.asset.metadata?.width) {
    console.log(`${result.asset.metadata.width}x${result.asset.metadata.height}`);
  }
}

Error Handling

interface DamPickerError {
  code: 'AUTHENTICATION_ERROR' | 'NETWORK_ERROR' | 'TIMEOUT' |
        'VALIDATION_ERROR' | 'UPLOAD_ERROR' | 'SCOPE_ERROR' | 'UNKNOWN';
  message: string;
}
Error CodeCause
AUTHENTICATION_ERRORInvalid, expired, or blocked token
NETWORK_ERRORNetwork connectivity issue
TIMEOUTPicker failed to load within timeout
VALIDATION_ERRORInvalid configuration options
UPLOAD_ERRORFile upload failed
SCOPE_ERRORToken missing required scope
UNKNOWNUnexpected error

Instance Methods

MethodReturnDescription
open()voidOpens the picker modal
close()voidCloses the picker modal
destroy()voidCleans up the instance and removes all DOM elements

Always call destroy() when you're done with the picker to prevent memory leaks.

Framework Examples

React (Hook)

import { useDamPicker } from '@fluid-app/dam-picker/react';

function ImageSelector() {
  const [imageUrl, setImageUrl] = useState<string | null>(null);
  const { open, isOpen } = useDamPicker({ token: 'pub-xxxxx' });

  return (
    <div>
      <button onClick={() => open({
        accept: ['image/*'],
        maxSize: 5,
        onSelect: (result) => setImageUrl(result.asset.url),
      })} disabled={isOpen}>
        Choose Image
      </button>
      {imageUrl && <img src={imageUrl} alt="Selected" />}
    </div>
  );
}

React (Controlled Component)

import { DamPickerModal } from '@fluid-app/dam-picker/react';

function ImageSelector() {
  const [isOpen, setIsOpen] = useState(false);
  const [imageUrl, setImageUrl] = useState<string | null>(null);

  return (
    <div>
      <button onClick={() => setIsOpen(true)}>Choose Image</button>
      {imageUrl && <img src={imageUrl} alt="Selected" />}

      <DamPickerModal
        isOpen={isOpen}
        token="pub-xxxxx"
        accept={['image/*']}
        maxFiles={1}
        maxSize={10}
        onSelect={(result) => {
          setImageUrl(result.asset.url);
          setIsOpen(false);
        }}
        onCancel={() => setIsOpen(false)}
      />
    </div>
  );
}

Vue 3

<script setup>
import { ref, onMounted, onUnmounted } from 'vue';
import { DamPicker } from '@fluid-app/dam-picker';

const imageUrl = ref(null);
let picker = null;

onMounted(() => {
  picker = new DamPicker({
    token: 'pub-xxxxx',
    accept: ['image/*'],
    onSelect: (result) => { imageUrl.value = result.asset.url },
  });
});

onUnmounted(() => picker?.destroy());
</script>

<template>
  <button @click="picker?.open()">Choose Image</button>
  <img v-if="imageUrl" :src="imageUrl" alt="Selected" />
</template>

Angular

import { Component, OnDestroy } from '@angular/core';
import { DamPicker } from '@fluid-app/dam-picker';

@Component({
  selector: 'app-image-selector',
  template: `
    <button (click)="openPicker()">Choose Image</button>
    <img *ngIf="imageUrl" [src]="imageUrl" alt="Selected" />
  `,
})
export class ImageSelectorComponent implements OnDestroy {
  imageUrl: string | null = null;
  private picker = new DamPicker({
    token: 'pub-xxxxx',
    accept: ['image/*'],
    onSelect: (result) => { this.imageUrl = result.asset.url },
  });

  openPicker() { this.picker.open() }
  ngOnDestroy() { this.picker.destroy() }
}

Content Security Policy

If your application uses a strict CSP, allow the picker iframe:

frame-src https://admin.fluid.app;

Additional Resources